MongoDB | 聚合 aggregate
2017-09-16 17:38
330 查看
聚合 aggregate
mongoDB官网mongoDB中文网
聚合(aggregate)主要用于计算数据,类似sql中的sum()、avg()
语法
db.集合名称.aggregate([{管道:{表达式}}])
管道
管道在Unix和Linux中一般用于将当前命令的输出结果作为下一个命令的输入ps -aux | grep mongo
在mongodb中,管道具有同样的作用,文档处理完毕后,通过管道进行下一次处理,管道操作是可以重复的。
常用管道
$group:将集合中的文档分组,可用于统计结果
$match:过滤数据,只输出符合条件的文档
$project:修改输入文档的结构,如重命名、增加、删除字段、创建计算结果
$sort:将输入文档排序后输出
$limit:限制聚合管道返回的文档数
$skip:跳过指定数量的文档,并返回余下的文档
$unwind:将数组类型的字段进行拆分
表达式
处理输入文档并输出表达式是无状态的,只能用于计算当前聚合管道的文档,不能处理其它的文档。
语法
#列名要加$ 表达式:'$列名'
常用表达式
$sum:计算总和,$sum:1同count表示计数
$avg:计算平均值
$min:获取最小值
$max:获取最大值
$push:在结果文档中插入值到一个数组中
$first:根据资源文档的排序获取第一个文档数据
$last:根据资源文档的排序获取最后一个文档数据
示例数据
> db.stu.find() { "_id" : ObjectId("59b8ed20fdefef4e475a942f"), "name" : "立夏", "gender" : 0, "age" : 25 } { "_id" : ObjectId("59b8ed4efdefef4e475a9430"), "name" : "王子", "gender" : 1, "age" : 20 } { "_id" : ObjectId("59b8eda8fdefef4e475a9431"), "name" : "上官玉", "gender" : 0, "age" : 20 } { "_id" : ObjectId("59b8ededfdefef4e475a9432"), "name" : "于萌", "gender" : 0, "age" : 15 } { "_id" : ObjectId("59b8fc98fdefef4e475a9433"), "name" : "夏至", "gender" : 1, "age" : 27 } { "_id" : ObjectId("59b8fdd2fdefef4e475a9434"), "name" : 0, "gender" : 0, "age" : 21 } { "_id" : ObjectId("59b8fdd2fdefef4e475a9435"), "name" : 2, "gender" : 1, "age" : 22 } { "_id" : ObjectId("59b8fdd2fdefef4e475a9436"), "name" : 3, "gender" : 0, "age" : 23 } { "_id" : ObjectId("59b8fdd2fdefef4e475a9437"), "name" : 4, "gender" : 1, "age" : 25 } { "_id" : ObjectId("59b8fdd2fdefef4e475a9438"), "name" : 5, "gender" : 0, "age" : 30 } { "_id" : ObjectId("59b8fdd2fdefef4e475a9439"), "name" : 6 } { "_id" : ObjectId("59b8fdd2fdefef4e475a943a"), "name" : 7 } { "_id" : ObjectId("59b8fdd2fdefef4e475a943b"), "name" : 8 } { "_id" : ObjectId("59b8fdd2fdefef4e475a943c"), "name" : 9 } { "_id" : ObjectId("59b93a99fdefef4e475a943d"), "name" : 1 } { "_id" : ObjectId("59ba38110686052694339d66"), "name" : "123" } { "_id" : ObjectId("59bb76d898a8f12a368878ef"), "gender" : 1, "age" : 20, "name" : "heey" }
$group
将集合中的文档分组,可用于统计结果_id表示分组的依据,使用某个字段的格式为 '$字段'
$sum:1 表示count计数
例:男生、女生的总人数
> db.stu.aggregate([ {$group:{ _id:'$gender', count:{$sum:1}} } ]) #结果 { "_id" : null, "count" : 6 } { "_id" : 1, "count" : 5 } { "_id" : 0, "count" : 6 }
例:男生、女生的总年龄
> db.stu.aggregate([ {$group:{ _id:'$gender', sumage:{$sum:'$age'}} } ]) #结果 { "_id" : null, "sumage" : 0 } { "_id" : 1, "sumage" : 114 } { "_id" : 0, "sumage" : 134 }
例:男生、女生的平均年龄
> db.stu.aggregate([ {$group:{ _id:'$gender', avg_age:{$avg:'$age'}} } ]) #结果 { "_id" : null, "avg_age" : null } { "_id" : 1, "avg_age" : 22.8 } { "_id" : 0, "avg_age" : 22.333333333333332 }
例:男生、女生的最小年龄
> db.stu.aggregate([ {$group:{ _id:'$gender', min_age:{$min:'$age'}} } ]) #结果 { "_id" : null, "min_age" : null } { "_id" : 1, "min_age" : 20 } { "_id" : 0, "min_age" : 15 }
Group by null
将集合中所有文档分为一组例:求学生总人数、平均年龄
> db.stu.aggregate([ {$group:{ _id:null, count:{$sum:1}, avg_age:{$avg:'$age'}} } ]) #结果 { "_id" : null, "count" : 17, "avg_age" : 22.545454545454547 }
透视数据 $push
例:统计学生性别及学生姓名> db.stu.aggregate([ {$group:{ _id:'$gender', name:{$push:'$name'}} } ]) #结果 { "_id" : null, "name" : [ 6, 7, 8, 9, 1, "123" ] } { "_id" : 1, "name" : [ "王子", "夏至", 2, 4, "heey" ] } { "_id" : 0, "name" : [ "立夏", "上官玉", "于萌", 0, 3, 5 ] }
使用$$ROOT可以将文档所有内容加入到结果集的数组中,代码如下
> db.stu.aggregate([ { $group:{ _id:'$gender', name:{$push:'$$ROOT'}} } ]).pretty() #结果 { "_id" : null, "name" : [ { "_id" : ObjectId("59b8fdd2fdefef4e475a9439"), "name" : 6 }, { "_id" : ObjectId("59b8fdd2fdefef4e475a943a"), "name" : 7 }, ...... ] } { "_id" : 1, "name" : [ { "_id" : ObjectId("59b8ed4efdefef4e475a9430"), "name" : "王子", "gender" : 1, "age" : 20 }, { "_id" : ObjectId("59b8fc98fdefef4e475a9433"), "name" : "夏至", "gender" : 1, "age" : 27 }, ...... ] } { "_id" : 0, "name" : [ { "_id" : ObjectId("59b8ed20fdefef4e475a942f"), "name" : "立夏", "gender" : 0, "age" : 25 }, { "_id" : ObjectId("59b8ededfdefef4e475a9432"), "name" : "于萌", "gender" : 0, "age" : 15 }, ...... ] }
$match
用于过滤数据,只输出符合条件的文档使用MongoDB的标准查询操作
例:查询年龄大于20的学生
> db.stu.aggregate([ {$match:{ age:{$gt:20}} } ]) #结果 { "_id" : ObjectId("59b8ed20fdefef4e475a942f"), "name" : "立夏", "gender" : 0, "age" : 25 } { "_id" : ObjectId("59b8fc98fdefef4e475a9433"), "name" : "夏至", "gender" : 1, "age" : 27 } { "_id" : ObjectId("59b8fdd2fdefef4e475a9434"), "name" : 0, "gender" : 0, "age" : 21 } { "_id" : ObjectId("59b8fdd2fdefef4e475a9435"), "name" : 2, "gender" : 1, "age" : 22 } { "_id" : ObjectId("59b8fdd2fdefef4e475a9436"), "name" : 3, "gender" : 0, "age" : 23 } { "_id" : ObjectId("59b8fdd2fdefef4e475a9437"), "name" : 4, "gender" : 1, "age" : 25 } { "_id" : ObjectId("59b8fdd2fdefef4e475a9438"), "name" : 5, "gender" : 0, "age" : 30 }
例:查询年龄大于20的男生、女生人数
> db.stu.aggregate([ {$match:{age:{$gt:20}}}, {$group:{_id:'$gender',count:{$sum:1}}} ]) #结果 { "_id" : 1, "count" : 3 } { "_id" : 0, "count" : 4 }
$project
修改输入4000
文档的结构,如重命名、增加、删除字段、创建计算结果
例:查询学生的姓名、年龄,_id是默认显示
> db.stu.aggregate([ {$project:{ _id:0, name:1, age:1} } ]) #结果 { "name" : "立夏", "age" : 25 } { "name" : "王子", "age" : 20 } { "name" : "上官玉", "age" : 20 } { "name" : "于萌", "age" : 15 } { "name" : "夏至", "age" : 27 } { "name" : 0, "age" : 21 } { "name" : 2, "age" : 22 } { "name" : 3, "age" : 23 } { "name" : 4, "age" : 25 } { "name" : 5, "age" : 30 } ......
例:查询男生、女生人数,输出人数
> db.stu.aggregate([ {$group:{_id:'$gender',count:{$sum:1}}}, {$project:{_id:0}} ]) #结果 { "count" : 6 } { "count" : 5 } { "count" : 6 } > db.stu.aggregate([ {$group:{_id:'$gender',count:{$sum:1}}}, {$project:{_id:0,count:1}} ]) #结果 { "count" : 6 } { "count" : 5 } { "count" : 6 }
$sort
将输入文档排序后输出1:升序 -1:降序
例:查询学生信息,按年龄升序
> db.stu.aggregate([ {$sort:{age:1}} ]) #结果 { "_id" : ObjectId("59b8fdd2fdefef4e475a9439"), "name" : 6 } { "_id" : ObjectId("59b8fdd2fdefef4e475a943a"), "name" : 7 } { "_id" : ObjectId("59b8fdd2fdefef4e475a943b"), "name" : 8 } { "_id" : ObjectId("59b8fdd2fdefef4e475a943c"), "name" : 9 } { "_id" : ObjectId("59b93a99fdefef4e475a943d"), "name" : 1 } { "_id" : ObjectId("59ba38110686052694339d66"), "name" : "123" } { "_id" : ObjectId("59b8ededfdefef4e475a9432"), "name" : "于萌", "gender" : 0, "age" : 15 } { "_id" : ObjectId("59b8ed4efdefef4e475a9430"), "name" : "王子", "gender" : 1, "age" : 20 } { "_id" : ObjectId("59b8eda8fdefef4e475a9431"), "name" : "上官玉", "gender" : 0, "age" : 20 } { "_id" : ObjectId("59bb76d898a8f12a368878ef"), "gender" : 1, "age" : 20, "name" : "heey" } { "_id" : ObjectId("59b8fdd2fdefef4e475a9434"), "name" : 0, "gender" : 0, "age" : 21 } { "_id" : ObjectId("59b8fdd2fdefef4e475a9435"), "name" : 2, "gender" : 1, "age" : 22 } { "_id" : ObjectId("59b8fdd2fdefef4e475a9436"), "name" : 3, "gender" : 0, "age" : 23 } { "_id" : ObjectId("59b8ed20fdefef4e475a942f"), "name" : "立夏", "gender" : 0, "age" : 25 } { "_id" : ObjectId("59b8fdd2fdefef4e475a9437"), "name" : 4, "gender" : 1, "age" : 25 } { "_id" : ObjectId("59b8fc98fdefef4e475a9433"), "name" : "夏至", "gender" : 1, "age" : 27 } { "_id" : ObjectId("59b8fdd2fdefef4e475a9438"), "name" : 5, "gender" : 0, "age" : 30 }
例:查询男生、女生人数,按人数降序
> db.stu.aggregate([ {$group:{_id:'$gender',count:{$sum:1}}}, {$sort:{count:-1}} ]) #结果 { "_id" : null, "count" : 6 } { "_id" : 0, "count" : 6 } { "_id" : 1, "count" : 5 }
$limit
限制聚合管道返回的文档数例:查询2条学生信息
> db.stu.aggregate([ {$limit:2} ]) #结果 { "_id" : ObjectId("59b8ed20fdefef4e475a942f"), "name" : "立夏", "gender" : 0, "age" : 25 } { "_id" : ObjectId("59b8ed4efdefef4e475a9430"), "name" : "王子", "gender" : 1, "age" : 20 }
$skip
跳过指定数量的文档,并返回余下的文档例:查询从第3条开始的学生信息
> db.stu.aggregate([ {$skip:3} ]) #结果 { "_id" : ObjectId("59b8ededfdefef4e475a9432"), "name" : "于萌", "gender" : 0, "age" : 15 } { "_id" : ObjectId("59b8fc98fdefef4e475a9433"), "name" : "夏至", "gender" : 1, "age" : 27 } { "_id" : ObjectId("59b8fdd2fdefef4e475a9434"), "name" : 0, "gender" : 0, "age" : 21 } { "_id" : ObjectId("59b8fdd2fdefef4e475a9435"), "name" : 2, "gender" : 1, "age" : 22 } ......
例:查询从第2条开始的5条学生信息
> db.stu.aggregate([ {$skip:1}, {$limit:5} ]) #结果 { "_id" : ObjectId("59b8ed4efdefef4e475a9430"), "name" : "王子", "gender" : 1, "age" : 20 } { "_id" : ObjectId("59b8eda8fdefef4e475a9431"), "name" : "上官玉", "gender" : 0, "age" : 20 } { "_id" : ObjectId("59b8ededfdefef4e475a9432"), "name" : "于萌", "gender" : 0, "age" : 15 } { "_id" : ObjectId("59b8fc98fdefef4e475a9433"), "name" : "夏至", "gender" : 1, "age" : 27 } { "_id" : ObjectId("59b8fdd2fdefef4e475a9434"), "name" : 0, "gender" : 0, "age" : 21 }
例:统计男生、女生人数,按人数升序,取第二条数据
> db.stu.aggregate([ {$group:{_id:'$gender',count:{$sum:1}}}, {$sort:{count:1}} ]) #结果 { "_id" : 1, "count" : 5 } { "_id" : null, "count" : 6 } { "_id" : 0, "count" : 6 } > db.stu.aggregate([ {$group:{_id:'$gender',count:{$sum:1}}}, {$sort:{count:1}}, {$skip:1}, {$limit:2} ]) #结果 { "_id" : null, "count" : 6 } { "_id" : 0, "count" : 6 }
注意顺序:先写skip,再写limit
使用sort与skip和limit合用时,结果有时会错乱
例
> db.stu.aggregate([{$sort:{age:1}},{$skip:2},{$limit:3}]) #正确结果应该是 name:8 9 1 { "_id" : ObjectId("59b93a99fdefef4e475a943d"), "name" : 1 } { "_id" : ObjectId("59b8fdd2fdefef4e475a943c"), "name" : 9 } { "_id" : ObjectId("59b8fdd2fdefef4e475a9439"), "name" : 6 }
$unwind
将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值语法1
对某字段值进行拆分db.集合名称.aggregate([{$unwind:'$字段名称'}])
构造数据
db.t2.insert({_id:1,item:'t-shirt',size:['S','M','L','XL']}) > db.t1.find() { "_id" : 1, "item" : "t-shirt", "size" : [ "S", "M", "L" ,"XL"] }
查询
> db.t2.aggregate({$unwind:'$size'}) { "_id" : 1, "item" : "t-shirt", "size" : "S" } { "_id" : 1, "item" : "t-shirt", "size" : "M" } { "_id" : 1, "item" : "t-shirt", "size" : "L" } { "_id" : 1, "item" : "t-shirt", "size" : "XL" }
语法2
对某字段值进行拆分处理空数组、非数组、无字段、null情况
db.inventory.aggregate([{ $unwind:{ path:'$字段名称', preserveNullAndEmptyArrays:#防止数据丢失 } }])
构造数据
db.t3.insert([ { "_id" : 1, "item" : "a", "size": [ "S", "M", "L"] }, { "_id" : 2, "item" : "b", "size" : [ ] }, { "_id" : 3, "item" : "c", "size": "M" }, { "_id" : 4, "item" : "d" }, { "_id" : 5, "item" : "e", "size" : null } ])
使用语法1查询
> db.t3.aggregate([{$unwind:'$size'}]) { "_id" : 1, "item" : "a", "size" : "S" } { "_id" : 1, "item" : "a", "size" : "M" } { "_id" : 1, "item" : "a", "size" : "L" } { "_id" : 3, "item" : "c", "size" : "M" }
查看查询结果,发现对于空数组、无字段、null的文档,都被丢弃了
问:如何能不丢弃呢?
答:使用语法2查询
> db.t3.aggregate([{$unwind:{path:'$sizes',preserveNullAndEmptyArrays:true}}]) { "_id" : 1, "item" : "a", "size" : [ "S", "M", "L" ] } { "_id" : 2, "item" : "b", "size" : [ ] } { "_id" : 3, "item" : "c", "size" : "M" } { "_id" : 4, "item" : "d" } { "_id" : 5, "item" : "e", "size" : null }
相关文章推荐
- MongoDB 聚合 aggregate
- MongoDB聚合运算之group和aggregate聚集框架简单聚合(10)
- 利用Mongodb聚合(aggregate)来进行复杂查询的技巧
- mongodb 之聚合框架--aggregate
- MongoDB的聚合(aggregate)
- MongoDB菜鸟入门(三):创建用户使用鉴权、使用聚合aggregate
- MongoDB中的数据聚合工具Aggregate和Group
- MongoDB中聚合(aggregate)的使用
- MongoDB聚合操作 (group, aggregate, mapReduce操作)
- 06-MongoDB聚合aggregate
- mongodb 聚合aggregate 乘法
- SQL到MongoDB的映射表(术语概率、CURD、aggregate聚合、Map-Reduce)
- mongodb-aggregate聚合日期分组
- Mongodb中数据聚合之聚合管道aggregate
- 工作日记2017.08.25 MongoDB 聚合查询 aggregate
- MongoDB中聚合工具Aggregate等的介绍与使用
- Mongodb中数据聚合之聚合管道aggregate
- MongoDB高级查询(二):对一个表中的2个字段中的"内嵌对象"中的字段进行比较----------- aggregate聚合查询
- MongoDB聚合
- 学习MongoDB 十一: MongoDB聚合(Aggregation Pipeline基础篇上)(三)