MongoDB中聚合(aggregate)主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果
每个文档通过一个由多个阶段(stage)组成的管道(可以对每个阶段的管道进行分组、过滤等功能),然后经过一系列的处理输出相应的结果
MongoDB中聚合方法使用aggregate()方法,语法格式如下:
db.集合名称.aggregate({管道:{表达式}})
MongoDB常用表达式:
表达式:用来处理输入文档并输出
语法:表达式:'$字段名' ----> avg_age: {$avg: "$age"}
管道
管道在Unix和Linux中一般用于将当前命令的输出结果作为下一个命令的输入,MongoDB聚合管道将MongoDB文档在一个管道处理完毕后的结果传递给下一个管道进行处理
表达式:处理输入文档并输出,表达式是无状态的,只能用于计算当前聚合管道的文档,不能处理其它的文档
聚合管道中常用的操作:
$group:将集合中的文档分组,可用于统计结果
$project:修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档
$match:用于过滤数据,只输出符合条件的文档($match使用MongoDB的标准查询操作)
$sort:将输入文档排序后输出
$limit:用来限制MongoDB聚合管道返回的文档数
$skip:在聚合管道中跳过指定数量的文档,并返回余下的文档
$unwind:将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值
$geoNear:输出接近某一地理位置的有序文档
1. $group:将集合中的文档按照某个字段分组(group后面有几个字段结果就有几个字段)
db.col.aggregate({$group: {_id:'$xxx', count: {$sum:1}}})
_id用来表示分组使用的字段,格式为$字段名
> db.test1.aggregate({$group:{_id:"$gender", count:{$sum:1}, avg_age:{$avg:"$age"}}})
{ "_id" : false, "count" : 2, "avg_age" : 18 }
{ "_id" : true, "count" : 5, "avg_age" : 27.8 }
将所有文档分为一组:group by null
db.col.aggregate({$group: {_id:null, count: {$sum:1}}})
按照多个字段分组:
db.col.aggregate(
{$group:{_id:{字段名:"$字段名", 字段名:"$字段名",.....}}}
)
如果一个键对应的值为字典类型,取值时可使用$字段名.键取其内部的值
2. $project:修改输入文档的结构,如重命名(as)、增加、删除字段、创建计算结果等(投影操作)
> db.test1.aggregate({$group:{_id:"$gender", count:{$sum:1}, avg_age:{$avg:"$age"}}})
{ "_id" : false, "count" : 2, "avg_age" : 18 }
{ "_id" : true, "count" : 5, "avg_age" : 27.8 }
> db.test1.aggregate(
... {$group:{_id:"$gender", counter:{$sum:1}, avg_age:{$avg:"$age"}}}, # 分组
... {$project:{gender:"$_id", count:"$counter", avg_age:"$avg_age", _id:0}} # 文档处理(投影处理)
... )
{ "gender" : false, "count" : 2, "avg_age" : 18 }
{ "gender" : true, "count" : 5, "avg_age" : 27.8 }
3. $match:用于过滤文档数据,输出符合条件的文档(使用标准查询操作)
- match是管道命令可将结果交给下一个管道,find不可以
> db.test1.aggregate(
... {$match:{age:{$gt:18}}},
... {$group:{_id:"$gender", counter:{$sum:1}, avg_age:{$avg:"$age"}}}
... )
{ "_id" : true, "counter" : 3, "avg_age" : 35 }
4. $sort:将输入文档排序后输出
> db.test1.aggregate(
... {$group:{_id:"$gender", counter:{$sum:1}}},
... {$sort:{counter:-1}}
... )
{ "_id" : true, "counter" : 5 }
{ "_id" : false, "counter" : 2 }
5. $limit和$skip
- $limit:限制聚合管道返回的文档数
- $skip:跳过指定数量的文档,并返回余下的文档(先写skip,再写limit)
> db.test1.aggregate({$limit:2})
{ "_id" : ObjectId("5e341734f059c66621de99fb"), "name" : "郭靖", "hometown" : "蒙古", "age" : 20, "gender" : true }
{ "_id" : ObjectId("5e34175df059c66621de99fc"), "name" : "黄蓉", "hometown" : "桃花岛", "age" : 18, "gender" : false }
> db.test1.aggregate(
... {$group:{_id:"$gender", counter:{$sum:1}}},
... {$sort:{counter:-1}},
... {$skip:1},
... {$limit:1}
... )
{ "_id" : false, "counter" : 2 }
6. $unwind:将文档中的某个数组类型字段拆分为多条,每条包含数组的一个值(展开)
```> db.info.insert({name:"朱翔", favorite:["王者荣耀", "刺激战场", "打麻将"]})
WriteResult({ "nInserted" : 1 })
> db.info.aggregate(
... {$unwind:"$favorite"}
... )
{ "_id" : ObjectId("5e34e40088cc04cff3d3bf4a"), "name" : "朱翔", "favorite" : "王者荣耀" }
{ "_id" : ObjectId("5e34e40088cc04cff3d3bf4a"), "name" : "朱翔", "favorite" : "刺激战场" }
{ "_id" : ObjectId("5e34e40088cc04cff3d3bf4a"), "name" : "朱翔", "favorite" : "打麻将" }