MongoDB Aggregations

  • 聚合框架
  • $project
  • $match
  • $limit
  • $skip
  • $unwind
  • $group
  • $sort
  • $out
  • $count
  • References


聚合框架

聚合框架是一种查询语言,可用于转换和组合来自多个文档的数据,以生成任何单个文档中都无法获得的新信息。

MongoDB中的聚合框架类似于SQL 中的GROUP BY和HAVING。

聚合框架过在一个数组中指定一系列操作并在一个调用中处理它,使得任务数据库搜索更加容易和高效。

聚合框架定义了一个聚合管道,其中管道中每个步骤的输出为下一步提供输入。

管道中的每个步骤都对输入文档执行一个操作,以转换输入并生成输出文档。

管道通过过滤、投影、分组、排序、限制和跳过等操作来处理文档流。

相同的操作可以在管道中以任何顺序重复多次。

$project

$project提取子文档的组件,重命名组件,并对组件执行操作。
选择每个部门的名称,跳过文档标识:

db.department.aggregate([ {"$project":{"name":1,"_id":0}} ])

选择每个部门的名称,并将其与代码连接起来:

db.document.aggregate([{"$project":{"Name and code":{"$concat":["$name","-","$code"]}}}])

Name and code是我们创建的$ project名,后面括号里的内容是$ project要进行的操作。
选择一个部门名称和10%的预算:

db.department.aggregate([ {"$project":{"name":1,
										"10% of budget":{"$multiply":["$budget",0.1]},
										"_id":0}
							}
						]
)

$match

$match操作选择了满足给定条件的文档。
找到预算> 10000的部门名称和代码:

db.department.aggregate([ {"$match":{"budget":{$gt:10000}}},
						{"$project":{"name":1,"code":1,"_id":0}} ])

$limit

$limit通过管道传递给定数量的文档。
找到预算>1000的第一份文件:

db.department.aggregate([ {"$match":{"budget":{"$gt":10000}}},
						  {"$limit":1} ]

limit:1代表第一,limit:2代表前2。

$skip

$skip从管道中消除给定数量的文档。

列出所有预算超过10000的文档,除了第一个:

db.department.aggregate([ {"$match":{"budget":{"$gt":10000}}},
						{"$skip":1}] )

注意skip与limit之间的区别,在什么情况下使用哪个。

$unwind

$unwind为给定数组的每个元素创建一个单独的文档。
数组的每个元素都复制一个文档,也就是说数组没有嵌套。

对于部门的每个系和每门课程创建一个单独的文件,只列出课程:

db.department.aggregate([ {"$unwind":"$courses"},
						{"$project":{"courses":1,"_id":0}} ])

找到所有12学分的课程:

db.department.aggregate([ {"$unwind":"$courses"},
						{"$project":{"courses":1,"_id":0}},
						{"$match":{"courses.credits":12}} ])

$group

$group对文档进行分组,并对每个组应用聚合函数。
按total_staff_number对文档进行分组,并列出total_staff_number的不同值

db.department.aggregate([ {"$group":{"_id":"$total_staff_number"}} ])

输出结果如下:

{ "_id" : 5 }
{ "_id" : 25 }

按照上面的方法进行分组,并将_id重命名为total_staff_number:

db.department.aggregate([ {"$group":{"_id":"$total_staff_number"}},
						{"$project":{"total_staff_number":"$_id","_id":0}} ])
{ "total_staff_number" : 5 }
{ "total_staff_number" : 25 }

按total_staff_number和预算对文件进行分组:

db.department.aggregate([ {"$group":{"_id":{"total_staff_number":"$total_staff_number",
											"budget":"$budget"},
{ "_id" : { "total_staff_number" : 5, "budget" : 10000 } }
{ "_id" : { "total_staff_number" : 25, "budget" : 100000 } }
{ "_id" : { "total_staff_number" : 25, "budget" : 1000000 } }

根据total_staff_number和每个组的平均预算对文件进行分组:

db.department.aggregate([ {"$group":{"_id":"$total_staff_number",
							"largest budget":{"$avg":"$budget"}}} ])

avg代表平均,同理如果找最大或最小的工资就用max或者min。

$sort

$sort对文档进行排序。
显示最大预算的部门名称,显示部门名称及其预算:

db.department.aggregate([ {"$project":{"name":1,"budget":1,"_id":0}},
						  {"$sort":{"budget":-1}},
						  {"$limit":1} ])

这里-1代表降序排列,最上面的是最大的,之后再limit 1,就把最大的筛选出来了。
同理1代表升序。

将文档按total_staff_number分组,统计每组中部门总数将结果按照部门总数降序排列:

db.department.aggregate([ {"$group":{"_id":"$total_staff_number",
									"total departments":{"$sum":1}}},
						 {"$sort":{"total departments":-1}} ])

输出结果:

{ "_id" : 25, "total departments" : 2 }
{ "_id" : 5, "total departments" : 1 }

$out

$out将处理结果保存在集合中。

找到total_staff_number不同值的总数:

db.department.aggregate([ {"$group":{"_id":"$total_staff_number"}},
						{"$out":"total_distinct"}])

db.total_distinct.count()
/*用完删除*/
db.total_distinct.drop()

$count

$count计算管道中文档的总数。

列出所有课程的代码:

db.department.aggregate([ {"$unwind":"$courses"},
						{"$project":{"code":"$courses.code","_id":0}},
						{"$count":"Total number of courses"} ])

MongoDB中的aggregate项目练习:

References

  1. Chodorow K. MongoDB The De?nitive Guide, O’Reilly, 2013.
  2. Banker K., Bakkum P., Verch S., Garret D., Hawkins T., MongoDB in Action, 2nd ed., Manning Publishers, 2016.