首页 / MONGODB / MongoDB中的聚合操作
MongoDB中的聚合操作
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了MongoDB中的聚合操作,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含7631字,纯文字阅读大概需要11分钟。
内容图文
根据MongoDB的文档描述,在MongoDB的聚合操作中,有以下五个聚合命令。
其中,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命令可以支持的选项:
1 { count: <collection>, query: <query>, limit: <limit>, skip: <skip>, hint: <hint> }
- count:要执行count的collection
- query(optional):过滤条件
- limit(optional):查询匹配文档数量的上限
- skip(optional):跳过匹配文档的数量
- hint(optional):使用那个索引
例子:查看男学生的数量
1 > db.runCommand({"count":"school.students", "query":{"gender":"Male"}}) 2 { "n" : 5, "ok" : 1 } 3 >
在MongoDB中,对count操作有一层包装,所以也可以通过shell直接运行db."collectionName".count()。
但是为了保持风格一致,我还是倾向于使用db.runCommand()的方式。
distinct
接下来看看distinct命令,下面列出可以支持的选项:
1 { distinct: "<collection>", key: "<field>", query: <query> }
- distinct:要执行distinct的collection
- key:要执行distinct的键
- query(optional):过滤条件
例子:查看所有学生年龄的不同值
1 > db.runCommand({"distinct":"school.students","key":"age"}) 2{ 3"values" : [ 420, 521, 622, 723, 824 9 ], 10"stats" : { 11"n" : 10, 12"nscanned" : 10, 13"nscannedObjects" : 0, 14"timems" : 0, 15"cursor" : "BtreeCursor age_1"16 }, 17"ok" : 118 }
group
group命令相比前两就稍微复杂了一些。
1 { 2 group: 3 { 4 ns: <namespace>, 5 key: <key>, 6 $reduce: <reduce function>, 7 initial: 8 $keyf: <key function>, 9 cond: <query>, 10 finalize: <finalize function> 11 } 12 }
- ns:要执行group的collection
- key:要执行group的键,可以是多个键;和keyf两者必须有一个
- $reduce:在group操作中要执行的聚合function,该function包括两个参数,当前文档和聚合结果文档
- initial:reduce中使用变量的初始化
- $keyf(optional):可以接受一个function,用来动态的确定分组文档的字段
- cond(optional):过滤条件
- finalize(optional):在reduce执行完成,结果集返回之前对结果集最终执行的函数
例子:统计不同年龄、性别分组的学生数量
1 > db.runCommand({ 2 ... "group":{ 3 ... "ns":"school.students", 4 ... "key":{"age":true, "gender":true}, 5 ... "initial":{"count":0}, 6 ... "$reduce": function(cur, result){ result.count++;}, 7 ... "cond":{"age":{"$lte":22}} 8... } 9... }) 10{ 11"retval" : [ 12 { 13"age" : 20, 14"gender" : "Female", 15"count" : 216 }, 17 { 18"age" : 20, 19"gender" : "Male", 20"count" : 121 }, 22 { 23"age" : 21, 24"gender" : "Male", 25"count" : 226 }, 27 { 28"age" : 22, 29"gender" : "Female", 30"count" : 131 } 32 ], 33"count" : 6, 34"keys" : 4, 35"ok" : 136} 37 >
通过finalize选项,可以在结果返回之前进行一些自定义设置。
1 > db.runCommand({ 2 ... "group":{ 3 ... "ns":"school.students", 4 ... "key":{"age":true, "gender":true}, 5 ... "initial":{"count":0}, 6 ... "$reduce": function(cur, result){ 7 ... result.count++; 8... }, 9 ... "cond":{"age":{"$lte":22}}, 10 ... "finalize": function(result){ 11 ... result.percentage = result.count/10; 12... delete result.count; 13... } 14... } 15... }) 16{ 17"retval" : [ 18 { 19"age" : 20, 20"gender" : "Female", 21"percentage" : 0.222 }, 23 { 24"age" : 20, 25"gender" : "Male", 26"percentage" : 0.127 }, 28 { 29"age" : 21, 30"gender" : "Male", 31"percentage" : 0.232 }, 33 { 34"age" : 22, 35"gender" : "Female", 36"percentage" : 0.137 } 38 ], 39"count" : 6, 40"keys" : 4, 41"ok" : 142} 43 >
mapReduce
前面三个聚合操作提供了最基本的功能,如果要用到更加复杂的聚合操作,我们就需要自己通过mapReduce来实现了。
mapReduce更重要的用法是实现多个服务器上的聚合操作。
根据MongoDB文档,得到mapReduce的原型如下:
1 { 2 mapReduce: <collection>, 3 map: <function>, 4 reduce: <function>, 5 out: <output>, 6 query(optional): <document>, 7sort(optional): <document>, 8 limit(optional): <number>, 9 finalize(optional): <function>, 10 scope(optional): <document>, 11 jsMode(optional): <boolean>, 12 verbose(optional): <boolean> 13 }
- 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文档
例子:
查询男生和女生的最大年龄
1 > db.runCommand({ 2 ... "mapReduce": "school.students", 3 ... "map": function(){ 4... emit({gender: this.gender}, this.age); 5... }, 6 ... "reduce": function(key, values){ 7 ... var max = 0; 8 ... for(var i = 0; i < values.length; i++) 9 ... max = max>values[i]?max:values[i]; 10... return max; 11... }, 12 ... "out": {inline: 1}, 13... 14... }) 15{ 16"results" : [ 17 { 18"_id" : { 19"gender" : "Female"20 }, 21"value" : 2422 }, 23 { 24"_id" : { 25"gender" : "Male"26 }, 27"value" : 2428 } 29 ], 30"timeMillis" : 2, 31"counts" : { 32"input" : 10, 33"emit" : 10, 34"reduce" : 2, 35"output" : 236 }, 37"ok" : 138} 39 >
分别得到男生和女生的平均年龄
1 > db.runCommand({ 2 ... "mapReduce": "school.students", 3 ... "map": function(){ 4... emit({gender: this.gender}, this.age); 5... }, 6 ... "reduce": function(key, values){ 7 ... var result = {"total": 0, "count": 0}; 8 ... for(var i = 0; i < values.length; i++) 9 ... result.total += values[i]; 10 ... result.count = values.length; 11... return result; 12... }, 13 ... "out": {inline: 1}, 14 ... "finalize": function(key, reducedValues){ 15 ... return reducedValues.total/reducedValues.count; 16... } 17... }) 18{ 19"results" : [ 20 { 21"_id" : { 22"gender" : "Female"23 }, 24"value" : 2225 }, 26 { 27"_id" : { 28"gender" : "Male"29 }, 30"value" : 21.831 } 32 ], 33"timeMillis" : 55, 34"counts" : { 35"input" : 10, 36"emit" : 10, 37"reduce" : 2, 38"output" : 239 }, 40"ok" : 141} 42 >
小技巧:关于自定义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中。
1 > db.runCommand({ 2 ... "mapReduce": "school.students", 3 ... "map": function(){ 4... emit({gender: this.gender}, this.age); 5... }, 6 ... "reduce": function(key, values){ 7 ... avg = Avg(key, values); 8... return avg; 9... }, 10 ... "out": {"merge": "average_age"} 11... }) 12{ 13"result" : "average_age", 14"timeMillis" : 30, 15"counts" : { 16"input" : 10, 17"emit" : 10, 18"reduce" : 2, 19"output" : 220 }, 21"ok" : 122} 23 >
通过以下命令,我们可以看到新增的collection,并且查看里面的内容。
1 > show collections 2average_age 3school.students 4system.indexes 5system.js 6 > 7 > db.average_age.find() 8 { "_id" : { "gender" : "Female" }, "value" : 22 } 9 { "_id" : { "gender" : "Male" }, "value" : 21.8 } 10 > 11 > db.system.js.find() 12 { "_id" : "Sum", "value" : function (key,values) 13{ 14 var total = 0; 15for(var i = 0; i < values.length; i++) 16 total += values[i]; 17 return total; 18} } 19 { "_id" : "Avg", "value" : function (key,values) 20{ 21 var total = Sum(key,values); 22 var mean = total/values.length; 23 return mean; 24} } 25 >
总结
通过这篇文章,介绍了MongoDB中count、distinct、group和mapReduce的基本使用。没有一次把所有的聚合操作都看完,聚合管道只能放在下一次了。
Ps: 文章中使用的例子可以通过以下链接查看
http://files.cnblogs.com/wilber2013/aggregation.js
原文:http://www.cnblogs.com/wilber2013/p/4141262.html
内容总结
以上是互联网集市为您收集整理的MongoDB中的聚合操作全部内容,希望文章能够帮你解决MongoDB中的聚合操作所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。