关键词:mongodb, mongo, project, group, aggregate, 聚合管道, 高级查询
简介
管道,即,前一个操作的输出(结果)是后一个操作的输入。
鸡蛋 -> 分出鸡蛋清 -> 加入牛奶并打发 -> 奶油
这就是一个管道,有四个阶段,前一个阶段的结果是后一个的输入。
叫管道,可能是因为看起来像一个管道
mongo 的管道操作
db.collection.aggregate( [ { <stage> }, ... ] )
例如,对user
文档进行管道聚合:
db.user.aggregate([
{第一个操作},
{第二个操作},
{第三个操作}
])
其中每个操作可以对应下面的任意一个:
例如有user
的库(collection)
{
username: 'abc',
password: '123'
}
1. $project「投影」
db.user.aggregate([
{
$project: {
username: 1
}
}
])
或者看起来是这样(为了和上面对比):
db.user.aggregate([
{ $project: {username: 1} }
])
查询结果:
{
username: 'abc'
}
1 == true
保留
0 == false
丢弃
下面同理
2. $match「匹配」
匹配出满足条件的数据项,条件与mongo查询条件一致
db.user.aggregate([
{ $match: { username: 'abc' } }
])
注意:如果需要按条件聚合的话,优先使用$match操作,会提高效率
例如应该这样:
db.user.aggregate([
{ $match: { username: 'abc' } }, // 放在首位
{ $project: { username: 1 } }
])
而不是这样:
db.user.aggregate([
{ $project: { username: 1 } },
{ $match: { username: 'abc' } }
])
3. $group「分组」
对数据进行分组,我一般用于统计使用,暂时没有用作其他
db.user.aggregate([
{ $group: {_id: '$username', sum: { $sum: 1 } } }
])
格式化一下:
db.user.aggregate([
{
$group: {
_id: '$username', // _id 是 group 操作的必须参数,即要分组的主键
sum_result: { $sum: 1 } // sum_result 是自定义结果字段,$sum 是操作符,这里意思是「加 1」
}
}
])
稍微解释一下:
_id 是必须的字段:
- 后面接 1 ,意思就是有多少条数据就返回多少条结果;
- 后面接字段名(即:"$ + 字段名" 形式),会以该字段进行分组,所有此字段的值相同的数据都将分到同一组;
sum_result 是自定义字段:
- 结果(value)为
{ $sum: 1 }
,即加1,也可以写成{ $sum: '$username' }
类似的字段名,如果该字段为数字,则累加数字; - 分到同一组的每条都将执行一次本操作,本示例得到的结果为,同名的用户个数统计
具体使用示例参考如下
请替换 collectionName 为自己所要操作的文档(库)名
db.collectionName.aggregate([
{
$match: { // 匹配 date 字段在 start_time 和 end_time 之间的数据
date: { $gt: start_time, $lt: end_time }
}
}, {
$project: { // 投影
user: 1,
type_1: { // 如果 type 字段等于 1,则 type_1 等于 1,否则为 null
$cond: [ { $eq: ['$type', 1 ] }, 1, null ]
},
type_2: { // 如果 type 字段等于 2,则 type_2 等于 1,否则为 null
$cond: [ { $eq: ['$type', 2 ] }, 1, null ]
}
}
}, {
$group: { // 分组
_id: '$user',
chat: {$sum: '$type_1'}, // 累加 type_1 字段
check: {$sum: '$type_2'} // 累加 type_2 字段
}
}
]);
举个栗子
去重复后的数量
db.collectionName.aggregate([
{
$match: {
isAdded: false // 一些筛选条件
}
}, {
$group: { // 分组
_id: '$content', // 需要去重的字段
}
}, {
$group: { // 分组
_id: 1,
count: {$sum: 1} // 去重之后的数量
}
}
]);
操作数组中的数据(相乘)
db.yourCollection.aggregate([
{
$match: {
type: "something your condition",
created_at: { $gte: new Date("2020-03-03T10:40:00"), $lt: new Date("2020-03-03T20:40:59") },
},
},
{
$project: {
draw_count: 1,
total_value: {
$reduce: {
input: "$items",
initialValue: 0,
in: { $add: ["$$value", { $multiply: ["$$this.item.value", "$$this.item.count"] }] },
},
},
},
},
{
$group: {
_id: "$draw_count",
count: { $sum: 1 },
value: { $sum: "$total_value" },
},
},
]);