文章目录
- 数据准备
- 条件查询
- 聚合查询
- 模糊查询
- 拆分数据
- 关联查询
- 根据用户组查询用户
- 根据用户查询用户组
- 控制显示
- 字段置顶
- 合并字段
- 新增或修改字段
- 计算总数
- 分页查询
- 分页查询加总数
- 排序
- 分组
数据准备
UserPO
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
@Document(collection = "user")
public class UserPO extends BasePO {
private String name;
private String description;
}
UserGroupPO
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
@Document(collection = "user_group")
public class UserGroupPO extends BasePO {
private String name;
private String description;
private List<Long> userIds;
}
用户数据
用户组数据
条件查询
match:and 匹配
查询用户组 id 等于 1,且删除标识等于 N 的数据
db.getCollection("user_group").aggregate([{
"$match": {
"$and": [{
"_id": NumberLong("1")
}, {
"deleteFlag": "N"
}]
}
}]);
match:or 匹配
查询用户 name 等于 nn 或者 description 等于 dd 的数据
db.getCollection("user").aggregate([{
"$match": {
"$or": [{
"name": "nn"
}, {
"description": "dd"
}]
}
}]);
聚合查询
查询用户组里的用户详情
模糊查询
match:按规则匹配
regex:按正则匹配
实现:按 xxx 模糊匹配字段 userName 或者 按 xxx 模糊匹配字段 userDes
db.getCollection("user").aggregate([{
"$match": {
"$or": [{
"userName": {
"$regex": ".*xxx.*"
}
}, {
"userDes": {
"$regex": ".*xxx.*"
}
}]
}
}]);
拆分数据
unwind:将文档中的某一个数组类型字段拆分成多条
实现:根据 userIds 把用户组拆分了多行
db.getCollection("user_group").aggregate([{
"$match": {
"$and": [{
"_id": NumberLong("2809813774582045833")
}, {
"deleteFlag": "N"
}]
}
}, {
"$unwind": "$userIds"
}]);
关联查询
根据用户组查询用户
lookup官方文档lookup:关联查询,类似于 MySQL 的 left jion 效果
实现:根据用户组的 userIds 查询用户详情,注意:查出来的 user 是个数组
- from:同一个数据库下等待被Join的集合。
- localField:源集合中的match值,如果输入的集合中,某文档没有 localField
这个Key(Field),在处理的过程中,会默认为此文档含
有 localField:null的键值对。 - foreignField:待Join的集合的match值,如果待Join的集合中,文档没有foreignField
值,在处理的过程中,会默认为此文档含有 foreignField:null的键值对。 - as:为输出文档的新增值命名。如果输入的集合中已存在该值,则会覆盖掉
db.getCollection("user_group").aggregate([{
"$match": {
"$and": [{
"_id": NumberLong("4523281346310580824")
}, {
"deleteFlag": "N"
}]
}
}, {
"$unwind": "$userIds"
}, {
"$lookup": {
"from": "user",
"localField": "userIds",
"foreignField": "_id",
"as": "user"
}
}]);
根据用户查询用户组
lookup:关联查询,类似于 MySQL 的 left jion 效果
实现:查询用户列表且包含对应的用户组信息,注意:查出来的 userGroups 是个数组
- from:要关联的从表名
- let:自定义变量,可以为多个
- pipeline:自定义的操作从表的聚合,但不允许使用out和merge操作,使用 let 定义的变量需要用两个$
- as:为输出文档的新增值命名。如果输入的集合中已存在该值,则会覆盖掉
db.getCollection("user").aggregate([{
$lookup: {
from: "user_group",
let: {
user_id: "$_id"
},
pipeline: [
{
$match: {
$expr: {
$in: ["$$user_id", "$userIds"]
}
}
}
],
as: "userGroups"
}
}]);
控制显示
project 控制字段显示与否
实现: 删除无用字段,
- 普通列({成员:1 | true}):表示要显示的内容
- “_id” 列({“_id”:0 | false}):表示 “_id” 列是否显示
db.getCollection("user_group").aggregate([{
"$match": {
"$and": [{
"_id": NumberLong("4523281346310580824")
}, {
"deleteFlag": "N"
}]
}
}, {
"$unwind": "$userIds"
}, {
"$lookup": {
"from": "user",
"localField": "userIds",
"foreignField": "_id",
"as": "user"
}
}, {
"$project": {
"user": 1,
"_id": 0,
}
}]);
字段置顶
arrayElemAt:将指定文档提升到顶级并替换所有其它字段。该操作会替换输入文档中的所有现在字段,包括_id字段
replaceRoot:返回存在于给定数组的指定索引上的元素
实现:把 user 的第一个元素提至顶级
db.getCollection("user_group").aggregate([{
"$match": {
"$and": [{
"_id": NumberLong("4523281346310580824")
}, {
"deleteFlag": "N"
}]
}
}, {
"$unwind": "$userIds"
}, {
"$lookup": {
"from": "user",
"localField": "userIds",
"foreignField": "_id",
"as": "user"
}
}, {
"$project": {
"user": 1,
"_id": 0,
}
}, {
"$replaceRoot": {
"newRoot": {
"$arrayElemAt": ["$user", 0]
}
}
}]);
此数据格式已经非常漂亮,符合日常返回格式,完成了需求
合并字段
mergeObjects:将多个文档合并为一个文档,如果要合并的文档包含相同的字段名,则结果文档中的字段具有该字段最后一个合并文档中的值
实现:保留 userGroup 的信息
db.getCollection("user_group").aggregate([{
"$match": {
"$and": [{
"_id": NumberLong("4523281346310580824")
}, {
"deleteFlag": "N"
}]
}
}, {
"$unwind": "$userIds"
}, {
"$lookup": {
"from": "user",
"localField": "userIds",
"foreignField": "_id",
"as": "user"
}
}, {
"$replaceRoot": {
"newRoot": {
"$mergeObjects": [{
"$arrayElemAt": ["$user", 0]
}, "$$ROOT"]
}
}
},{
"$project": {
"user": 0
}
}]);
新增或修改字段
set:字段存在则修改,无则新增
实现:
db.getCollection("user_group").aggregate([{
"$match": {
"$and": [{
"_id": NumberLong("4523281346310580824")
}, {
"deleteFlag": "N"
}]
}
}, {
"$unwind": "$userIds"
}, {
"$lookup": {
"from": "user",
"localField": "userIds",
"foreignField": "_id",
"as": "user"
}
}, {
"$replaceRoot": {
"newRoot": {
"$mergeObjects": [{
"$arrayElemAt": ["$user", 0]
}, "$$ROOT"]
}
}
}, {
"$project": {
"user": 0
}
}, {
"$set": {
"accounts": "accounts",
"deleteFlag": "deleteFlag"
}
}]);
计算总数
count:计算总数
实现:查询 user 表的总条数
db.getCollection("user").aggregate([
{
"$count": "total"
}
]);
分页查询
分页:对数据做分页处理
跳过 3 条数据,从第 4 条起,显示 2 条
- skip:跳过多少条
- limit:显示多少条
db.getCollection("user").aggregate([
{
"$skip": 3
},
{
"$limit": 2
}
]);
分页查询加总数
分页查询需要同时返回总数和数据
facet:在同一组输入文档的单一阶段中处理多个聚合管道;每个子管道在输出文档中都有自己的字段,其结果存储在文档数组中
db.getCollection("user").aggregate([
{
"$facet": {
"metadata": [{
"$count": "total"
}],
"records": [{
"$skip": 0
}, {
"$limit": 10
}]
}
}
]);
metadata 不太符合常规数据结构,把它去掉,把 total 提上顶层
db.getCollection("user").aggregate([
{
"$facet": {
"metadata": [{
"$count": "total"
}],
"records": [{
"$skip": 0
}, {
"$limit": 2
}]
}
},
{
"$replaceRoot": {
"newRoot": {
"$mergeObjects": [{
"$arrayElemAt": ["$metadata", 0]
}, "$$ROOT"]
}
}
},
{
"$project": {
"metadata": 0
}
}
]);
排序
sort:根据某字段对数据进行排序
其中 key 用来定义要根据那个字段进行排序,后面的值 1 则表示以升序进行排序,若要以降序进行排序则需要将其设置为 -1
实现:对用户表按创建时间倒序来排序
db.getCollection("user").aggregate([
{
$sort: {
creationDate: - 1
}
}
]);
分组
$group :根据某字段对数据进行分组,类似 MySQL的 group by
- _id :强制必须存在。可以为 null
- $sum:计算总数
- $avg:计算平均值
- $max:最大值
- $min:最小值
- $first:输出第一个内容
- $last:输出最后一个内容
- $push:将数据拼接到一个数组中
- $addToSet:将数据拼接到一个数组中,过滤重复数据
数据准备
$sum:根据用户的 userName 字段,对数据进行分组,并统计重复的总数
db.getCollection("user").aggregate([{
$group: {
_id: "$userName",
count: {
$sum: 1
}
}
}]);
$avg:根据用户的 userName 字段,对数据进行分组,并算出分组后 userDes 的平均值
db.getCollection("user").aggregate([{
$group: {
_id: "$userName",
desavg: {
$avg: "$userDes"
}
}
}]);
$push:根据用户的 userName 字段,对数据进行分组,并把 userDes 组合到 num
db.getCollection("user").aggregate([{
$group: {
_id: "$userName",
num: {
$push: "$userDes"
}
}
}]);
$addToSet:和push类似,但会过滤重复的数据,name2 的 40 只有一条了
db.getCollection("user").aggregate([{
$group: {
_id: "$userName",
num: {
$addToSet: "$userDes"
}
}
}]);
$$ROOT:分组后生成list
db.getCollection("user").aggregate([{
$group: {
_id: "$userName",
num: {
$push: "$$ROOT"
}
}
}]);