Mongodb的聚合和管道

时间:2023-03-08 17:14:46

MongoDB 聚合

MongoDB中聚合(aggregate)主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果。


aggregate() 方法

MongoDB中聚合的方法使用aggregate()。

语法

aggregate() 方法的基本语法格式如下所示:

>db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)

注:参数AGGREGATE_OPERATION可以是一个对象(单个处理),也可以是多个对象的数组(管道处理)。

> db.person.find()

{ "_id" : ObjectId("592ffd872108e8e79ea902b0"), "name" : "zjf", "age" : 30 }

{ "_id" : ObjectId("593011c8a92497992cdfac10"), "name" : "xhj", "age" : 30 }

{ "_id" : ObjectId("59301270a92497992cdfac11"), "name" : "zzj", "age" : 2 }

{ "_id" : ObjectId("593015fda92497992cdfac12"), "name" : "my second child", "age" : "i do not know" }

//$group代表分组 分组的内容里的是要返回的列的名称 第一列的名称_id是不能改变的 代表以它进行分组 后面的列是汇总列 可以随便明明 $sum是汇总的方式 1是汇总的内容 可以是列如’$age’ 也可以是数值 此处 sum(1)就是count(*)的意思了。

> db.person.aggregate({$group : {_id: '$age', count : {$sum : 1}}})

{ "_id" : "i do not know", "count" : 1 }

{ "_id" : 2, "count" : 1 }

{ "_id" : 30, "count" : 2 }

$group : 将集合中的文档分组,可用于统计结果,$group首先将数据根据key进行分组。

$group语法: { $group: { _id: <expression>, <field1>: { <accumulator1> : <expression1> }, ... } }

_id 是要进行分组的key

$group:可以分组的数据执行如下的表达式计算:

$sum:计算总和。

$avg:计算平均值。

$min:根据分组,获取集合中所有文档对应值得最小值。

$max:根据分组,获取集合中所有文档对应值得最大值。

$push:将指定的表达式的值添加到一个数组中。

$addToSet:将表达式的值添加到一个集合中(无重复值)。

$first:返回每组第一个文档,如果有排序,按照排序,如果没有按照默认的存储的顺序的第一个文档。

$last:返回每组最后一个文档,如果有排序,按照排序,如果没有按照默认的存储的顺序的最后个文档。

对多列进行分组:

{ "$group" : { "_id" : { "citycode":"$citycode" , "uid" : "$uid"  } , "count":{ "$sum" : 1 } } }

管道操作的限制:

每个阶段管道限制为100MB的内存。如果一个节点管道超过这个极限,MongoDB将产生一个错误。为了能够在处理大型数据集,可以设置allowDiskUse为true来在聚合管道节点把数据写入临时文件。这样就可以解决100MB的内存的限制。

这个限制可能最新版本会没有了,如果用到的时候可以去https://docs.mongodb.com/查一查官方手册。

管道的概念

管道在Unix和Linux中一般用于将当前命令的输出结果作为下一个命令的参数。

MongoDB的聚合管道将MongoDB文档在一个管道处理完毕后将结果传递给下一个管道处理。管道操作是可以重复的。

表达式:处理输入文档并输出。表达式是无状态的,只能用于计算当前聚合管道的文档,不能处理其它的文档。

这里我们介绍一下聚合框架中常用的几个操作:

  • $project:修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档。
  • $match:用于过滤数据,只输出符合条件的文档。$match使用MongoDB的标准查询操作。
  • $limit:用来限制MongoDB聚合管道返回的文档数。
  • $skip:在聚合管道中跳过指定数量的文档,并返回余下的文档。
  • $unwind:将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。
  • $group:将集合中的文档分组,可用于统计结果。
  • $sort:将输入文档排序后输出。
  • $geoNear:输出接近某一地理位置的有序文档。

管道操作符实例

1、$project实例

db.article.aggregate(

{ $project : {

title : 1 ,

author : 1 ,

}}

);

这样的话结果中就只还有_id,tilte和author三个字段了,默认情况下_id字段是被包含的,如果要想不包含_id话可以这样:

db.article.aggregate(

{ $project : {

_id : 0 ,

title : 1 ,

author : 1

}});

2.$match实例

db.articles.aggregate( [

{ $match : { score : { $gt : 70, $lte : 90 } } },

{ $group: { _id: null, count: { $sum: 1 } } }

] );

$match用于获取分数大于70小于或等于90记录,然后将符合条件的记录送到下一阶段$group管道操作符进行处理。

3.$skip实例

db.article.aggregate(

{ $skip : 5 });

经过$skip管道操作符处理后,前五个文档被"过滤"掉。

性能相关:

尽早在管道里尝试减少文档的数量和大小。

索引只能用于$match和$sort操作。可以大大的提升性能。

在$match和$sort之外的操作符不能使用索引。

如果使用分片,那么$match和$project将在每个分片上执行,但是其他操作符将在主要分片上执行。(这个主要分片是什么,我没有在官方手册中找到,官方手册中只有路由,配置服务器,分片这些概念)

在聚合管道中,一个步骤的结果将输出给下一个步骤,如果下一个步骤提前执行完毕,如limit,那么会通知上一个步骤,上一个步骤也会停止。