MongoDB的聚合操作分为两种:
- pipeline聚合
- mapReduce聚合
mapReduce聚合:通过自定义的聚合命令,实现聚合操作,自由度高,适合大数据量且复杂的聚合操作
pipeline聚合
使用MongoDB提供的聚合命令,速度快,只能运行在单机上,适合小数据量的实时聚合操作,且在资源的使用上有一定的限制:单个聚合操作耗费的内存不能超过20%;返回的结果集大小小于16M
1. 语法说明
db.collection.aggregate(match,project,group, …)
aggredate 方法接收任意多个参数,每个参数都是一个具体类别的聚合操作,通过参数的顺序组成一个执行链。每个操作执行的结果交给下一个操作,直到最后返回结果集。
2. pipeline聚合命令(运算符)
$match 条件过滤
# 查找名字为学生1的文档
db.student.aggregate({$match:{name:"学生1"}})
$project 指定列返回
# 给返回的列取别名
db.student.aggregate({$project:{"姓名":"$name"}})
# 限定返回的字段
db.student.aggregate({$project:{_id: 0, "姓名":"$name"}})
# 如果不特别指定,_id属性是默认返回的,这里的0也可以是false或者返回为false的表达式
# $name 表示对name属性的引用
$group
必须指定 _id 列
db.student.aggregate({$group:{_id:"$age", "count":{$sum:1}}})
$sum 求和
db.student.aggregate({$group:{_id:"$age", "count":{$sum:1}}})
$max 求最大值
db.student.aggregate({$group:{_id:"$sex", maxAge:{$max:"$age"}}})
$push 添加列表
db.student.aggregate({$group:{_id:"$sex", names:{$push:"$name"}}})
$addToSet 添加列表并去重
db.student.aggregate({$group:{_id:"$sex", names:{$addToSet:"$age"}}})
$first 取第一个值
db.student.aggregate({$group:{_id:"$sex", firstOne:{$first:"$name"}}})
$last 取最后一个值
db.student.aggregate({$group:{_id:"$sex", lastOne:{$last:"$name"}}})
$sort 排序
db.student.aggregate({$project:{name: 1, age: 1}},{ $sort:{ "age":1}})
$limit 用来限制返回的文档数
db.student.aggregate({$project:{name: 1, age: 1}},{ $sort:{ "age":1}},{$limit:4})
$skip 跳过指定数量的文档,返回剩余文档
db.student.aggregate({$project:{name: 1, age: 1}},{ $sort:{ "age":1}},{$limit:4}, {$skip:2})
db.student.aggregate({$project:{name: 1, age: 1}},{ $sort:{ "age":1}},{$skip:2},{$limit:4})
#unwind 将数组拆分成多条记录
db.student.aggregate({$project:{name: 1, subject: 1}}, {$unwind:"$subject"})
3. mapRedurce 聚合
mapRedurce 非常适合实现非常复杂 并且数量大的聚合计算,其可运行在多台节点上实行分布式计算。
# mapReduce的命令方式
db.collection.mapReduce(
map, //map函数(生成键值对序列,作为 reduce 函数参数)
reduce, //reduce函数
{
<out>, //存放输出结果的集合,不写使用临时集合
<query>, //筛选条件,符合条件才会进入map
<sort>, //排序
<limit>, //限制条数
<finalize>,
<scope>,
<jsMode>,
<verbose>
}
)
创建Map函数
var map1 = function(){emit(this.sex,1)}
# emit为mapReduce的内置函数, 这里以sex字段进行分组,1就是值
# emit({sex:this.sex,age: this.age}, this)
创建Reduce函数
var reduce1 = function(key, values){return Array.sum(values);}
# 如果reduce函数中直接返回values.lengthz,在values只有一个值时会输出原值,而不是1
执行mapReduce聚合操作,将结果输出到新的结果集
var reduce1 = function(key, values){return Array.sum(values);}
查询上一步输出的结果集
db.result.find()
# 也可以直接在上一步的后边直接使用find
db.student.mapReduce(map1, reduce1, {out:"result"}).find()