MongoDB中的聚合操作
2014-12-03 22:24
330 查看
根据MongoDB的文档描述,在MongoDB的聚合操作中,有以下五个聚合命令。
其中,count、distinct和group会提供很基本的功能,至于其他的高级聚合功能(sum、average、max、min),就需要通过mapReduce来实现了。
在MongoDB2.2版本以后,引入了新的聚合框架(聚合管道,aggregation pipeline ,使用aggregate命令),是一种基于管道概念的数据聚合操作。
下面就开始对这些聚合操作进行介绍,所有的测试数据都是基于上一篇文章。
count:要执行count的collection
query(optional):过滤条件
limit(optional):查询匹配文档数量的上限
skip(optional):跳过匹配文档的数量
hint(optional):使用那个索引
例子:查看男学生的数量
在MongoDB中,对count操作有一层包装,所以也可以通过shell直接运行db."collectionName".count()。
但是为了保持风格一致,我还是倾向于使用db.runCommand()的方式。
distinct:要执行distinct的collection
key:要执行distinct的键
query(optional):过滤条件
例子:查看所有学生年龄的不同值
ns:要执行group的collection
key:要执行group的键,可以是多个键;和keyf两者必须有一个
$reduce:在group操作中要执行的聚合function,该function包括两个参数,当前文档和聚合结果文档
initial:reduce中使用变量的初始化
$keyf(optional):可以接受一个function,用来动态的确定分组文档的字段
cond(optional):过滤条件
finalize(optional):在reduce执行完成,结果集返回之前对结果集最终执行的函数
例子:统计不同年龄、性别分组的学生数量
通过finalize选项,可以在结果返回之前进行一些自定义设置。
mapReduce更重要的用法是实现多个服务器上的聚合操作。
根据MongoDB文档,得到mapReduce的原型如下:
mapReduce:要执行map-reduce操作的collection
map:map function,生成键/值对,可以理解为映射函数
reduce:reduce function,对map的结果进行统计,可以理解为统计函数
out:统计结果存放集合 (不指定则使用临时集合,在客户端断开后自动删除)
query:过滤条件
sort:排序条件
limit:map函数可以接受的文档数量的最大值
finalize:在reduce执行完成后,结果集返回之前对结果集最终执行的函数
scope:向 map、reduce、finalize 导入外部变量
jsMode:设置是否把map和reduce的中间数据转换成BSON格式
verbose:设置是否显示详细的时间统计信息
注意:map、reduce和finalize的函数实现都有特定的要求,具体的要求请参考MongoDB文档
例子:
查询男生和女生的最大年龄
分别得到男生和女生的平均年龄
小技巧:关于自定义js函数
在MongoDB中,可以通过db.system.js.save命令(其中system.js是一个存放js函数的collections)来创建并保存JavaScript函数,这样在就可以在MongoDB shell中重用这些函数。
比如,下面两个函数是网上网友实现的
通过利用上面两个函数,我们的"分别得到男生和女生的平均年龄"例子就可以通过以下方式实现。
这个例子中,我们还特殊设置了"out"选项,把返回值存入了"average_age"这个collection中。
通过以下命令,我们可以看到新增的collection,并且查看里面的内容。
Ps: 文章中使用的例子可以通过以下链接查看
http://files.cnblogs.com/wilber2013/aggregation.js
其中,count、distinct和group会提供很基本的功能,至于其他的高级聚合功能(sum、average、max、min),就需要通过mapReduce来实现了。
在MongoDB2.2版本以后,引入了新的聚合框架(聚合管道,aggregation pipeline ,使用aggregate命令),是一种基于管道概念的数据聚合操作。
Name | Description |
count | Counts the number of documents in a collection. |
distinct | Displays the distinct values found for a specified key in a collection. |
group | Groups documents in a collection by the specified key and performs simple aggregation. |
mapReduce | Performs map-reduce aggregation for large data sets. |
aggregate | Performs aggregation tasks such as group using the aggregation framework. |
count
首先,我们看下MongoDB文档中,count命令可以支持的选项:{ count: <collection>, query: <query>, limit: <limit>, skip: <skip>, hint: <hint> }
count:要执行count的collection
query(optional):过滤条件
limit(optional):查询匹配文档数量的上限
skip(optional):跳过匹配文档的数量
hint(optional):使用那个索引
例子:查看男学生的数量
> db.runCommand({"count":"school.students", "query":{"gender":"Male"}}) { "n" : 5, "ok" : 1 } >
在MongoDB中,对count操作有一层包装,所以也可以通过shell直接运行db."collectionName".count()。
但是为了保持风格一致,我还是倾向于使用db.runCommand()的方式。
distinct
接下来看看distinct命令,下面列出可以支持的选项:{ distinct: "<collection>", key: "<field>", query: <query> }
distinct:要执行distinct的collection
key:要执行distinct的键
query(optional):过滤条件
例子:查看所有学生年龄的不同值
> db.runCommand({"distinct":"school.students","key":"age"}) { "values" : [ 20, 21, 22, 23, 24 ], "stats" : { "n" : 10, "nscanned" : 10, "nscannedObjects" : 0, "timems" : 0, "cursor" : "BtreeCursor age_1" }, "ok" : 1 }
group
group命令相比前两就稍微复杂了一些。{ group: { ns: <namespace>, key: <key>, $reduce: <reduce function>, initial: $keyf: <key function>, cond: <query>, finalize: <finalize function> } }
ns:要执行group的collection
key:要执行group的键,可以是多个键;和keyf两者必须有一个
$reduce:在group操作中要执行的聚合function,该function包括两个参数,当前文档和聚合结果文档
initial:reduce中使用变量的初始化
$keyf(optional):可以接受一个function,用来动态的确定分组文档的字段
cond(optional):过滤条件
finalize(optional):在reduce执行完成,结果集返回之前对结果集最终执行的函数
例子:统计不同年龄、性别分组的学生数量
> db.runCommand({ ... "group":{ ... "ns":"school.students", ... "key":{"age":true, "gender":true}, ... "initial":{"count":0}, ... "$reduce": function(cur, result){ result.count++;}, ... "cond":{"age":{"$lte":22}} ... } ... }) { "retval" : [ { "age" : 20, "gender" : "Female", "count" : 2 }, { "age" : 20, "gender" : "Male", "count" : 1 }, { "age" : 21, "gender" : "Male", "count" : 2 }, { "age" : 22, "gender" : "Female", "count" : 1 } ], "count" : 6, "keys" : 4, "ok" : 1 } >
通过finalize选项,可以在结果返回之前进行一些自定义设置。
> db.runCommand({ ... "group":{ ... "ns":"school.students", ... "key":{"age":true, "gender":true}, ... "initial":{"count":0}, ... "$reduce": function(cur, result){ ... result.count++; ... }, ... "cond":{"age":{"$lte":22}}, ... "finalize": function(result){ ... result.percentage = result.count/10; ... delete result.count; ... } ... } ... }) { "retval" : [ { "age" : 20, "gender" : "Female", "percentage" : 0.2 }, { "age" : 20, "gender" : "Male", "percentage" : 0.1 }, { "age" : 21, "gender" : "Male", "percentage" : 0.2 }, { "age" : 22, "gender" : "Female", "percentage" : 0.1 } ], "count" : 6, "keys" : 4, "ok" : 1 } >
mapReduce
前面三个聚合操作提供了最基本的功能,如果要用到更加复杂的聚合操作,我们就需要自己通过mapReduce来实现了。mapReduce更重要的用法是实现多个服务器上的聚合操作。
根据MongoDB文档,得到mapReduce的原型如下:
{ mapReduce: <collection>, map: <function>, reduce: <function>, out: <output>, query(optional): <document>, sort(optional): <document>, limit(optional): <number>, finalize(optional): <function>, scope(optional): <document>, jsMode(optional): <boolean>, verbose(optional): <boolean> }
mapReduce:要执行map-reduce操作的collection
map:map function,生成键/值对,可以理解为映射函数
reduce:reduce function,对map的结果进行统计,可以理解为统计函数
out:统计结果存放集合 (不指定则使用临时集合,在客户端断开后自动删除)
query:过滤条件
sort:排序条件
limit:map函数可以接受的文档数量的最大值
finalize:在reduce执行完成后,结果集返回之前对结果集最终执行的函数
scope:向 map、reduce、finalize 导入外部变量
jsMode:设置是否把map和reduce的中间数据转换成BSON格式
verbose:设置是否显示详细的时间统计信息
注意:map、reduce和finalize的函数实现都有特定的要求,具体的要求请参考MongoDB文档
例子:
查询男生和女生的最大年龄
> db.runCommand({ ... "mapReduce": "school.students", ... "map": function(){ ... emit({gender: this.gender}, this.age); ... }, ... "reduce": function(key, values){ ... var max = 0; ... for(var i = 0; i < values.length; i++) ... max = max>values[i]?max:values[i]; ... return max; ... }, ... "out": {inline: 1}, ... ... }) { "results" : [ { "_id" : { "gender" : "Female" }, "value" : 24 }, { "_id" : { "gender" : "Male" }, "value" : 24 } ], "timeMillis" : 2, "counts" : { "input" : 10, "emit" : 10, "reduce" : 2, "output" : 2 }, "ok" : 1 } >
分别得到男生和女生的平均年龄
> db.runCommand({ ... "mapReduce": "school.students", ... "map": function(){ ... emit({gender: this.gender}, this.age); ... }, ... "reduce": function(key, values){ ... var result = {"total": 0, "count": 0}; ... for(var i = 0; i < values.length; i++) ... result.total += values[i]; ... result.count = values.length; ... return result; ... }, ... "out": {inline: 1}, ... "finalize": function(key, reducedValues){ ... return reducedValues.total/reducedValues.count; ... } ... }) { "results" : [ { "_id" : { "gender" : "Female" }, "value" : 22 }, { "_id" : { "gender" : "Male" }, "value" : 21.8 } ], "timeMillis" : 55, "counts" : { "input" : 10, "emit" : 10, "reduce" : 2, "output" : 2 }, "ok" : 1 } >
小技巧:关于自定义js函数
在MongoDB中,可以通过db.system.js.save命令(其中system.js是一个存放js函数的collections)来创建并保存JavaScript函数,这样在就可以在MongoDB shell中重用这些函数。
比如,下面两个函数是网上网友实现的
SUM | db.system.js.save( { _id : "Sum" , value : function(key,values) { var total = 0; for(var i = 0; i < values.length; i++) total += values[i]; return total; }}); |
AVERAGE | db.system.js.save( { _id : "Avg" , value : function(key,values) { var total = Sum(key,values); var mean = total/values.length; return mean; }}); |
这个例子中,我们还特殊设置了"out"选项,把返回值存入了"average_age"这个collection中。
> db.runCommand({ ... "mapReduce": "school.students", ... "map": function(){ ... emit({gender: this.gender}, this.age); ... }, ... "reduce": function(key, values){ ... avg = Avg(key, values); ... return avg; ... }, ... "out": {"merge": "average_age"} ... }) { "result" : "average_age", "timeMillis" : 30, "counts" : { "input" : 10, "emit" : 10, "reduce" : 2, "output" : 2 }, "ok" : 1 } >
通过以下命令,我们可以看到新增的collection,并且查看里面的内容。
> show collections average_age school.students system.indexes system.js > > db.average_age.find() { "_id" : { "gender" : "Female" }, "value" : 22 } { "_id" : { "gender" : "Male" }, "value" : 21.8 } > > db.system.js.find() { "_id" : "Sum", "value" : function (key,values) { var total = 0; for(var i = 0; i < values.length; i++) total += values[i]; return total; } } { "_id" : "Avg", "value" : function (key,values) { var total = Sum(key,values); var mean = total/values.length; return mean; } } >
总结
通过这篇文章,介绍了MongoDB中count、distinct、group和mapReduce的基本使用。没有一次把所有的聚合操作都看完,聚合管道只能放在下一次了。Ps: 文章中使用的例子可以通过以下链接查看
http://files.cnblogs.com/wilber2013/aggregation.js
相关文章推荐
- MongoDB:详细解释mongodb的高级操作,聚合和游标
- 第8周 Mongodb的游标,索引,聚合操作与MapReduce
- Mongodb的游标,索引,聚合操作与MapReduce
- mongodb 索引、聚合操作
- python操作mongodb之二聚合查询
- MongoCola使用教程 1 - MongoDB的基本操作和聚合功能
- MongoDB学习笔记——聚合操作之MapReduce
- mongodb的高级操作(游标、聚合)
- mongodb与sql聚合操作对应图
- MongoDB 聚合操作
- mongodb 高级操作:聚合,游标
- MongoDB入门教程之聚合和游标操作介绍
- MongoDB 用实例学习聚合操作
- mongodb的高级操作(聚合框架)
- MongoDB:详细解释mongodb的高级操作,聚合和游标
- java对MongoDB的聚合操作(BasicDBObject)
- mongodb的高级操作(聚合框架)
- mongodb 聚合操作 操作符
- MongoDB学习笔记——聚合操作之group,distinct,count