聚合 是泛指各种可以处理批量记录并返回计算结果的操作。MongoDB提供了丰富的聚合操作,用于对数据集执行计算操作。在 mongod 实例上执行聚合操作可以大大简化应用的代码,并降低对资源的消耗。

聚合有比较简单的 count 计算总数;distinct去重;group by 分组。也有比较复杂的管道聚合。下面将分别讲述。

appuser 集合 具有如下文档
{name:"人间四月",age:,"locate":" 北京"}
{name:"dolphin",age:,"locate":" 北京"}
{name:"yunsheng",age:,"locate":" 天津"}
{name:"shark",age:,"locate":" 天津"}
{name:"babywang",age:,"locate":" 四川"}

count 返回符合查询条件的文档总数

使用mongodb命令查询北京地区的注册人数
db.appuser.count({locate:"北京"})
返回结果是 []

distinct去除重复操作 返回查询到的指定字段值不重复的记录

使用mongodb命令查询用户来自于哪些地区
db.appuser.distinct("locate")
返回结果是 [" 北京"," 天津","四川"]

count distinct 配合使用

使用mongodb命令查询用户来源的地区数量
db.runCommand({"distinct":"appuser","key":"locate"}).values.length
返回结果是

group 操作会把查询到的文档按照给定的字段值进行分组。分组操作会返回一个文档数组,其中的每个文档包含了一组文档的计算结果

group 命令不能在分片集合上运行。特别需要注意一点, group 操作的结果集大小不能超过16MB。

mongodb命令查询各个地区 年龄最大的用户

db.appuser.group({
key:{locate:""},
initial:{age:},
reduce:function(cur, result){
if(cur.age>result.age)
result.age = cur.age;
result.name = cur.name;
}})
查询返回结果是
[ {
waitedMS:NumberLong(),
retval:[{
locate:" 北京",
age:22.0,
name:"dolphin"
},{
locate:" 天津",
age:23.0,
name:"shark"
},{
locate:" 四川",
age:25.0,
name:"babywang"
}],
count:NumberLong(),
keys:NumberLong(),
ok:1.0
}]
group $keyf 有时 我们需要对分组的字段做一些处理。
mongodb命令 对名字长度分组,找出每个分组中年龄最大的用户。
db.appuser.group({
$keyf:function(doc){return {namelength:doc.name.length};},
initial:{age:},
reduce:function(cur, result){
if(cur.age>result.age)
result.age = cur.age;
result.name = cur.name;
}
})
返回结果[
{
waitedMS:NumberLong(),
retval:[
{
namelength:4.0,
age:20.0,
name:"人间四月"
},
{
namelength:7.0,
age:22.0,
name:"dolphin"
},
{
namelength:8.0,
age:25.0,
name:"babywang"
},
{
namelength:5.0,
age:23.0,
name:"shark"
}
],
count:NumberLong(),
keys:NumberLong(),
ok:1.0
}
]

group finalize 针对分组后的每一个分组结果做相应操作
mongodb命令 对名字长度分组,找出每个分组中年龄最大的用户,最后对每个人的年龄加10
db.appuser.group({
$keyf:function(doc){return {namelength:doc.name.length};},
initial:{age:},
finalize:function(doc){
doc.age=doc.age+;
},
reduce:function(cur, result){
if(cur.age>result.age)
result.age = cur.age;
result.name = cur.name;
}
})

作者:dolphin叔叔
链接:http://www.jianshu.com/p/5b32d7612d08
來源:简书

聚合管道的功能简单来说就分两种:

  • 对文档进行“过滤”,也就是筛选出符合条件的文档;
  • 对文档进行“变换”,也就是改变文档的输出形式。

####$project#### 1.我们有这样的数据

  {
"_id" : 1,
title: "abc123",
isbn: "0001122223334",>
author: { last: "zzz", first: "aaa" },
copies: 5
}

现在使用project来变换输出

 db.books.aggregate(
[
{ $project : { title : 1 , author : 1 } }
]
)

可以得

 {
"_id" : 1,
"title" : "abc123",
"author" : { "last" : "zzz", "first" : "aaa" }
}

在$project里,我们指明(筛选)了要显示的数据,title和author,_id是自带的,可以用 _id:0 来将其过滤掉

2.我们现在有基础数据

 {
"_id" : 1,
title: "abc123",
isbn: "0001122223334",
author: { last: "zzz", first: "aaa" },
copies: 5
}

但是我们需要变换他的输出形式,我们就可以这样

db.books.aggregate(
[
{
$project: {
title: 1,
isbn: {
prefix: { $substr: [ "$isbn", 0, 3 ] },
group: { $substr: [ "$isbn", 3, 2 ] },
publisher: { $substr: [ "$isbn", 5, 4 ] },
title: { $substr: [ "$isbn", 9, 3 ] },
checkDigit: { $substr: [ "$isbn", 12, 1] }
},
lastName: "$author.last",
copiesSold: "$copies"
}
}
]
)

在isbn内部的键 prefix,group,publisher,title,checkDigit,外部的lastName,copiesSold都是我们自己定义的。 $substr取字串,$isbn是字串键名,第二参数是字串起始位置,第三参数是取几个。

最后结果

 {
"_id" : 1,
"title" : "abc123",
"isbn" : {
"prefix" : "000",
"group" : "11",
"publisher" : "2222",
"title" : "333",
"checkDigit" : "4"
},
"lastName" : "zzz",
"copiesSold" : 5
}

数据源没有变,但是我们改变的数据显示的方式。

####$match#### 过滤数据,过滤完的数据,接下来用作其他用。 (水龙头上的过滤器,过滤干净的水,接下来淘米,煮饭都可以,貌似扯远了。。。回!)

1.例子

  db.articles.aggregate(
[
{ $match : { author : "dave" } }
]
);

过滤条件为键 author 值为 dave

结果为

 {
"result" : [
{
"_id" : ObjectId("512bc95fe835e68f199c8686"),
"author": "dave",
"score" : 80
},
{ "_id" : ObjectId("512bc962e835e68f199c8687"),
"author" : "dave",
"score" : 85
}
],
"ok" : 1
}

2.再看一例

 db.articles.aggregate(
[
{ $match : { score : { $gt : 70, $lte : 90 } } },
{ $group: { _id: null, count: { $sum: 1 } } }
]
);

这次有两步:

  • 第一步,过滤 键 score 值 大于70 且 小于等于90 的文档,
  • 再用group 对文档用 count 统计,统计方式 $sum 求和,步长为1。

因为group操作必须有个_id,所以给其置null。

结果为

 {
"result" : [
{
"_id" : null,
"count" : 3
}
],
"ok" : 1
}

####$cond#### 判断用的,可以跟if then 语句

1.举例

{ "_id" : 1, "item" : "abc1", qty: 300 }

{ "_id" : 2, "item" : "abc2", qty: 200 }

{ "_id" : 3, "item" : "xyz1", qty: 250 }

现在我们想根据qty的值来生成新的数据(值)

db.inventory.aggregate(
[
{
$project:
{
item: 1,
discount:
{
$cond: { if: { $gte: [ "$qty", 250 ] }, then: 30, else: 20 }
}
}
}
]
)

结果为

 { "_id" : 1, "item" : "abc1", "discount" : 30 }
{ "_id" : 2, "item" : "abc2", "discount" : 20 }
{ "_id" : 3, "item" : "xyz1", "discount" : 30 }

可以发现,discount是我们新的键,它根据cond的if判断后,分别被赋上了相应的值(then和else可以省略)

####$limit#### 限制个数

1.例子

db.article.aggregate(
{ $limit : 5 }
);

值得注意的是,当聚合操作中同时出现sort和limit, sort只会对通过limit的数据排序,内存中也仅会存储通过limit的数据。

####$skip#### 略过N个

1.例子

db.article.aggregate(
{ $skip : 5 }
);

####$unwind#### 拆解数组集合

1.例子

 {
"_id" : 1,
"item" : "ABC1",
sizes: [ "S", "M", "L"]
}

现在对sizes进行拆解

 db.inventory.aggregate(
[
{ $unwind : "$sizes" }
]
)

结果

 { "_id" : 1, "item" : "ABC1", "sizes" : "S" }
{ "_id" : 1, "item" : "ABC1", "sizes" : "M" }
{ "_id" : 1, "item" : "ABC1", "sizes" : "L" }

我们可以看到sizes里每一个数据被拆解到每一个文档里了,除了sizes 的值不同外,其他相同。

$unwind与$group组合可以实现distinct

####$group#### 先分组,再合并

1.例子

{ "_id" : { "month" : 3, "day" : 15, "year" : 2014 },
"totalPrice" : 50, "averageQuantity" : 10, "count" : 1 } { "_id" : { "month" : 4, "day" : 4, "year" : 2014 },
"totalPrice" : 200, "averageQuantity" : 15, "count" : 2 } { "_id" : { "month" : 3, "day" : 1, "year" : 2014 },
"totalPrice" : 40, "averageQuantity" : 1.5, "count" : 2 }

_id 为分组依据,_id 为null,及不分组,直接合并。

合并依据:

  • 键 totalPrice 保存 键 price 和 键 quantity 值 的乘积 的和

  • 键averageQuantity 保存 键 quantity 的值的平均值

  • 键 count 作统计

    db.sales.aggregate( [ { $group : { _id : null, totalPrice: { $sum: { $multiply: [ "$price", "$quantity" ] } }, averageQuantity: { $avg: "$quantity" }, count: { $sum: 1 } } } ] )

结果

 { "_id" : null, "totalPrice" : 290, "averageQuantity" : 8.6, "count" : 5 }

2.再看一例

 { "_id" : 1, "item" : "abc", "price" : 10, "quantity" : 2,
"date" : ISODate("2014-03-01T08:00:00Z") } { "_id" : 2, "item" : "jkl", "price" : 20, "quantity" : 1,
"date" : ISODate("2014-03-01T09:00:00Z") } { "_id" : 3, "item" : "xyz", "price" : 5, "quantity" : 10,
"date" : ISODate("2014-03-15T09:00:00Z") } { "_id" : 4, "item" : "xyz", "price" : 5, "quantity" : 20,
"date" : ISODate("2014-04-04T11:21:39.736Z") } { "_id" : 5, "item" : "abc", "price" : 10, "quantity" : 10,
"date" : ISODate("2014-04-04T21:23:13.331Z") }

咱们依据 键 item 分组

  db.sales.aggregate( [ { $group : { _id : "$item" } } ] )

结果

 { "_id" : "xyz" }
{ "_id" : "jkl" }
{ "_id" : "abc" }

####$sort#### 排序

1.例子

db.users.aggregate(
[
{ $sort : { age : -1, posts: 1 } }
]
)

对键age 顺序排序,对键 posts 逆序排序

####$out#### 创建指定副本集合

1.例子

   { "_id" : 8751, "title" : "The Banquet", "author" : "Dante", "copies" : 2 }

   { "_id" : 8752, "title" : "Divine Comedy", "author" : "Dante", "copies" : 1 }

   { "_id" : 8645, "title" : "Eclogues", "author" : "Dante", "copies" : 2 }

   { "_id" : 7000, "title" : "The Odyssey", "author" : "Homer", "copies" : 10 }

   { "_id" : 7020, "title" : "Iliad", "author" : "Homer", "copies" : 10 }

对其按author分组,然后out一个新集合authors

  db.books.aggregate( [
{ $group : { _id : "$author", books: { $push: "$title" } } },
{ $out : "authors" }
] )

结果

 { "_id" : "Homer", "books" : [ "The Odyssey", "Iliad" ] }
{ "_id" : "Dante", "books" : [ "The Banquet", "Divine Comedy", "Eclogues" ] }

我们现在看到的只是数据映射,不是实体文档,

但是在authors里,有映射副本存成的文档。

也就是说 $out 可以创建新的集合,存储聚合后的文档映射。

转自https://github.com/qianjiahao/MongoDB/wiki/MongoDB%E4%B9%8B%E8%81%9A%E5%90%88%E7%AE%A1%E9%81%93%E4%B8%8A

mongodb聚合(转)的更多相关文章

  1. MongoDB 聚合管道(Aggregation Pipeline)

    管道概念 POSIX多线程的使用方式中, 有一种很重要的方式-----流水线(亦称为"管道")方式,"数据元素"流串行地被一组线程按顺序执行.它的使用架构可参考 ...

  2. Mongodb学习笔记四(Mongodb聚合函数)

    第四章 Mongodb聚合函数 插入 测试数据 ;j<;j++){ for(var i=1;i<3;i++){ var person={ Name:"jack"+i, ...

  3. mongodb MongoDB 聚合 group

    MongoDB 聚合 MongoDB中聚合(aggregate)主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果.有点类似sql语句中的 count(*). 基本语法为:db.col ...

  4. MongoDB 聚合

    聚合操作过程中的数据记录和计算结果返回.聚合操作分组值从多个文档,并可以执行各种操作,分组数据返回单个结果.在SQL COUNT(*)和group by 相当于MongoDB的聚集. aggregat ...

  5. MongoDB聚合

    --------------------MongoDB聚合-------------------- 1.aggregate():     1.概念:         1.简介             ...

  6. MongoDB 聚合分组取第一条记录的案例及实现

    关键字:MongoDB: aggregate:forEach 今天开发同学向我们提了一个紧急的需求,从集合mt_resources_access_log中,根据字段refererDomain分组,取分 ...

  7. mongodb MongoDB 聚合 group(转)

    MongoDB 聚合 MongoDB中聚合(aggregate)主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果.有点类似sql语句中的 count(*). 基本语法为:db.col ...

  8. mongodb聚合 group

    MongoDB中聚合(aggregate)主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果.有点类似sql语句中的 count(*). 基本语法为:db.collection.agg ...

  9. MongoDB 聚合(管道与表达式)

    MongoDB中聚合(aggregate)主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果.有点类似sql语句中的 count(*). aggregate() 方法 MongoDB中 ...

  10. 【Mongodb教程 第十一课 】MongoDB 聚合

    聚合操作过程中的数据记录和计算结果返回.聚合操作分组值从多个文档,并可以执行各种操作,分组数据返回单个结果.在SQL COUNT(*)和group by 相当于MongoDB的聚集. aggregat ...

随机推荐

  1. C++格式输出控制

    #include<iostream> #include<string> #include<vector> #include<set> #include& ...

  2. Deep Learning关于Vision的Reading List

    最近开始学习深度学习了,加油! 下文转载自:http://blog.sina.com.cn/s/blog_bda0d2f10101fpp4.html 主要是顺着Bengio的PAMI review的文 ...

  3. 虚拟机vmware下安装Ghost XP——正确的解决方案

    http://hi.baidu.com/xjl456852/item/fd466e9935b2da8859146111 在虚拟机中启动系统,出现"Operating System not f ...

  4. 利用ResultFilter实现asp.net mvc3 页面静态化

    为了提高网站性能.和网站的负载能力,页面静态化是一种有效的方式,这里对于asp.net mvc3 构架下的网站,提供一种个人认为比较好的静态话方式. 实现原理是通过mvc提供的过滤器扩展点实现页面内容 ...

  5. [libgdx游戏开发教程]使用Libgdx进行游戏开发(2)-游戏框架搭建

    让我们抛开理论开始code吧. 入口类CanyonBunnyMain的代码: package com.packtpub.libgdx.canyonbunny; import com.badlogic. ...

  6. RAID磁盘恢复方法之一Winhex镜像硬盘与镜像中恢复数据图文

    winhex镜像硬盘和ghost备份是完全不同的,ghost只能克隆或者镜像分区内正常的数据,删除的数据他是不会克隆的,所以在数据恢复应用中,ghost对我们来讲作用就不大了,而使用winhex备份( ...

  7. 如何使用Jenkins进行持续集成测试

    如何使用Jenkins进行持续集成测试: 安装Java环境: 安装Jenkins:两种方式,直接运行文件:使用tomcat运行: 创建一个job,构建的时候选择 execute Windows bat ...

  8. centos6.5 的rpm 可以来这边找

    http://copr-be.cloud.fedoraproject.org/results/mosquito/myrepo-el6/epel-6-i386/gcc-4.8.2-16.3.fc20/

  9. python判断一个数是否是2的几次幂

    判断一个数是不是2的几次幂,最简单粗暴的做法就是直接迭代除以2,这里有一个更好的方法,那就是采用位运算. 我们观察下面属于2的几次幂的数的变化规律,用2进制表示. 十进制 二进制 0 0 2 10 4 ...

  10. Unity防破解 —— 重新编译mono

        Unity4.x版本导出android包时,只能选择mono,无法使用il2cpp,这就造成了我们的程序集很容易被修改--很多朋友在发布项目时觉得即使代码暴露出去也没什么关系,只有项目火了才有 ...