根据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命令可以支持的选项:

 { 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" : , "ok" : }
>

在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" : [
,
,
,
, ],
"stats" : {
"n" : ,
"nscanned" : ,
"nscannedObjects" : ,
"timems" : ,
"cursor" : "BtreeCursor age_1"
},
"ok" :
}

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":},
... "$reduce": function(cur, result){ result.count++;},
... "cond":{"age":{"$lte":}}
... }
... })
{
"retval" : [
{
"age" : ,
"gender" : "Female",
"count" :
},
{
"age" : ,
"gender" : "Male",
"count" :
},
{
"age" : ,
"gender" : "Male",
"count" :
},
{
"age" : ,
"gender" : "Female",
"count" :
}
],
"count" : ,
"keys" : ,
"ok" :
}
>

通过finalize选项,可以在结果返回之前进行一些自定义设置。

 > db.runCommand({
... "group":{
... "ns":"school.students",
... "key":{"age":true, "gender":true},
... "initial":{"count":},
... "$reduce": function(cur, result){
... result.count++;
... },
... "cond":{"age":{"$lte":}},
... "finalize": function(result){
... result.percentage = result.count/;
... delete result.count;
... }
... }
... })
{
"retval" : [
{
"age" : ,
"gender" : "Female",
"percentage" : 0.2
},
{
"age" : ,
"gender" : "Male",
"percentage" : 0.1
},
{
"age" : ,
"gender" : "Male",
"percentage" : 0.2
},
{
"age" : ,
"gender" : "Female",
"percentage" : 0.1
}
],
"count" : ,
"keys" : ,
"ok" :
}
>

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 = ;
... for(var i = ; i < values.length; i++)
... max = max>values[i]?max:values[i];
... return max;
... },
... "out": {inline: },
...
... })
{
"results" : [
{
"_id" : {
"gender" : "Female"
},
"value" :
},
{
"_id" : {
"gender" : "Male"
},
"value" :
}
],
"timeMillis" : ,
"counts" : {
"input" : ,
"emit" : ,
"reduce" : ,
"output" :
},
"ok" :
}
>

分别得到男生和女生的平均年龄

 > db.runCommand({
... "mapReduce": "school.students",
... "map": function(){
... emit({gender: this.gender}, this.age);
... },
... "reduce": function(key, values){
... var result = {"total": , "count": };
... for(var i = ; i < values.length; i++)
... result.total += values[i];
... result.count = values.length;
... return result;
... },
... "out": {inline: },
... "finalize": function(key, reducedValues){
... return reducedValues.total/reducedValues.count;
... }
... })
{
"results" : [
{
"_id" : {
"gender" : "Female"
},
"value" :
},
{
"_id" : {
"gender" : "Male"
},
"value" : 21.8
}
],
"timeMillis" : ,
"counts" : {
"input" : ,
"emit" : ,
"reduce" : ,
"output" :
},
"ok" :
}
>

小技巧:关于自定义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" : ,
"counts" : {
"input" : ,
"emit" : ,
"reduce" : ,
"output" :
},
"ok" :
}
>

通过以下命令,我们可以看到新增的collection,并且查看里面的内容。

 > show collections
average_age
school.students
system.indexes
system.js
>
> db.average_age.find()
{ "_id" : { "gender" : "Female" }, "value" : }
{ "_id" : { "gender" : "Male" }, "value" : 21.8 }
>
> db.system.js.find()
{ "_id" : "Sum", "value" : function (key,values)
{
var total = ;
for(var i = ; 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中的聚合操作的更多相关文章

  1. 在MongoDB中实现聚合函数

    在MongoDB中实现聚合函数 随着组织产生的数据爆炸性增长,从GB到TB,从TB到PB,传统的数据库已经无法通过垂直扩展来管理如此之大数据.传统方法存储和处理数据的成本将会随着数据量增长而显著增加. ...

  2. MongoDB学习笔记——聚合操作之MapReduce

    MapReduce MongoDB中的MapReduce相当于关系数据库中的group by.使用MapReduce要实现两个函数Map和Reduce函数.Map函数调用emit(key,value) ...

  3. 在MongoDB中使用JOIN操作

    SQL与NoSQL最大的不同之一就是不支持JOIN,在传统的数据库中,SQL JOIN子句允许你使用普通的字段,在两个或者是更多表中的组合表中的每行数据.例如,如果你有表books和publisher ...

  4. 在MongoDB中实现聚合函数 (转)

    随着组织产生的数据爆炸性增长,从GB到TB,从TB到PB,传统的数据库已经无法通过垂直扩展来管理如此之大数据.传统方法存储和处理数据的成本将会随着数据量增长而显著增加.这使得很多组织都在寻找一种经济的 ...

  5. MongoDB 基本操作和聚合操作

    一 . MongoDB 基本操作 基本操作可以简单分为查询.插入.更新.删除. 1 文档查询 作用 MySQL SQL  MongoDB  所有记录  SELECT * FROM users;  db ...

  6. Numpy 中的聚合操作

    # 导包 import numpy as np sum np.random.seed(10) L = np.random.random(100) sum(L) np.sum(L) min np.min ...

  7. mongodb 数据库中 的聚合操作

  8. MongoDB学习笔记——聚合操作之聚合管道(Aggregation Pipeline)

    MongoDB聚合管道 使用聚合管道可以对集合中的文档进行变换和组合. 管道是由一个个功能节点组成的,这些节点用管道操作符来进行表示.聚合管道以一个集合中的所有文档作为开始,然后这些文档从一个操作节点 ...

  9. MongoDB学习笔记——聚合操作之group,distinct,count

    单独的聚合命令(group,distinct,count) 单独聚合命令 比aggregate性能低,比Map-reduce灵活度低:但是可以节省几行javascript代码,后面那句话我自己加的,哈 ...

随机推荐

  1. 【驱动】——seq_file使用指南

    seq_file只是在普通的文件read中加入了内核缓冲的功能,从而实现顺序多次遍历,读取大数据量的简单接口.seq_file一般只提供只读接口,在使用seq_file操作时,主要靠下述四个操作来完成 ...

  2. 【css】css 背景色渐变兼容写法

    最近在项目中,有很多地方都用到了线性渐变,比如:表单提交按钮的背景,数据展示的标题背景等等,按照以前的做法是切 1px 图片然后 repeat-x.下面我将介绍如何用 css 来完成该效果. css3 ...

  3. jQuery(十一):jQuery的事件

    一.jQuery事件的分类 jQuery事件是对JavaScript事件的封装,常用事件分类如下: 1.基础事件 window事件. 鼠标事件. 键盘事件. 表单事件. 2.复合事件是多个事件的组合 ...

  4. linux下shellcode提取常用到的命令

    汇编语言的汇编指令: nasm -f elf xxx.asm    生成xxx.o文件 ld -o xxx  xxx.o  生成可执行文件,不用加参数-s ,否则在提取shellcode的十六进制码的 ...

  5. SparkR(R on Spark)编程指南 含 dataframe操作

    SparkR(R on Spark)编程指南 Spark  2015-06-09 28155  1评论 下载为PDF    为什么不允许复制 关注iteblog_hadoop公众号,并在这里评论区留言 ...

  6. 关于Unity中Shader的基础认识

    Shader也叫着色器,是Unity里面比较难的一个点,网上有很多别人写好的shader,我们可以下载下来用或者修改学习. Shader可以做出很多非常不错的效果,因为它是插在渲染管道里面的程序,一来 ...

  7. Cocos2d-x绘制圆角矩形

    /* * @brief 画圆角矩形 * @param origin 矩形开始点 * @param destination 矩形结束点 * @param radius 圆角半径 * @param seg ...

  8. 【转】【MySQL】Mysql模糊查询like提速优化

    在使用msyql进行模糊查询的时候,很自然的会用到like语句,通常情况下,在数据量小的时候,不容易看出查询的效率,但在数据量达到百万级,千万级的时候,查询的效率就很容易显现出来.这个时候查询的效率就 ...

  9. struts+ajax+jquery:实现异步新增数据

    很久未有更新,最近因为团队其它事耽误没有继续学习,但心中十分忐忑不安,抽空把自己薄弱的点拿来再巩固一下! 本身异步刷新用处非常多,SSH框架对我来讲,已无难度,但结合ajax处理一些增删查改分页等,就 ...

  10. qualcomm lk gpio

    关于高通平台lk中控制gpio的记录 http://blog.csdn.net/loongembedded/article/details/72834761 http://blog.csdn.net/ ...