MongoDB3.2 之 aggregate的管道符详述

概述:
众所周知,aggregate是mongodb非常强大的工具之一,之所以强大是因为它可以像乐高一样随意摆放各种组件(当然还是要遵守一定规则的)
注:aggregation就是单线程的,每个请求每个片一个线程。
 
简介:
下面我们就对aggregate的pipeline进行一一解释;
汇总:
  • 1. $match:  匹配查询条件,针对的是源集合,可多次使用;
  • 2. $limit: 限制输出的结果集 ;
  • 3. $lookup: left join其他集合,且两个集合必须在一个库下 ;
  • 4. $group: 类似于关系型数据库的group by,其后也可以加上诸多操作,比如$sum,$max,$min
  • 5. $unwind: 分裂数组,重组数据 ;
  • 6.$project: 字段重命名,字段做运算,合并,选择性的增加或删除字段;
  • 7.$sort: 排序, 类似 order by
  • 8.$skip: 省略某些行,类似find()后面的skip()
  • 9.$redact: document内容的判断和"修剪”;
  • 10.$sample: 随机选取指定数量的document;
  • 11.$out: 将结果集输出到指定collection中;
  • 12.$indexStats: 统计collection中的索引使用信息;
  • 13.$geoNear: 根据位置信息查找最近和最远的点
  • 14.$bucket: 根据某一个字段范围条件分组,然后分组计算、收集其他字段值等操作(我的理解,比较复杂,3.4新功能)
  • 15.$addFields: 输出从上一管道符接受到的所有字段,并添加新字段(3.4新特性,类似于$project)
  • 16.$bucketAuto
  • 17.$collStats: 返回一个集合的统计信息(3.4新特性)
  • 18.$count: 计算上一个管道符结果集的文档数量
  • 19.$facet:
  • 20.$graphLookup
  • 21.$listSessions
  • 22.$listLocalSessions
  • 23.$replaceRoot
  • 24.$sortByCount
  • 25.$currentOp
 
注:其中的某些stage可以在一个aggregate语句中重复使用,比如$match,$group,$limit;这样可以进行更细化的数据处理
数据集合
 
使用方法详述
下面就简单介绍一下各个组件的使用方法:
1、$project:
     遍历文档的指定字段到下一个stage(阶段);
     意思就是说可以过滤掉某些字段(包括过滤掉_id)、可以重命名字段、添加新的字段,重置字段的值
     语法:
{ $project: { <specifications> } }     
     
<specifications>的选项
描述
<field>:  <1  or  true>
执行显示哪些字段
_id:  <0  or  false>
过滤掉_id字段
<field>:  <expression>
添加新字段或者重置字段的值
     举例:
     
2、$match:
     查询需要的数据给到下一个stage;
     如果放到aggregate开端的话,可以利用上索引,与find()中的query语法一致
     语法:
{ $match: { <query> } }     ---query中写什么呢?就是在find()中写的东东
     举例:
3、$limit:
     其实就是做一个行数的限制,类似top 10 *
     语法:
{ $limit: <positive integer> }
     举例:
 
4、$lookup:
      left join同一库下的另一集合去过滤数据,
语法:
  $lookup:
    {
      from: <collection to join>,     ---left join后的那个集合名称
      localField: <field from the input documents>,     ---用于链接的源集合的字段名
      foreignField: <field from the documents of the "from" collection>,     ---left join后的集合的链接字段
      as: <output array field>     ---从另一集合链接过来的数据会存放在一个数组中,这是写该数组的名称
    }
}
 
注:如果你想要使用源集合中的数组的某个元素作为链接字段,那么你就需要考虑使用$unwind了,什么?你还不懂$unwind是什么?那就继续向下看吧
     举例:
     
5、$unwind:
     分裂数组,重组数据(document)
语法:
{
  $unwind:
    {
      path: <field path>,     ---你想要分裂的数组名称
      includeArrayIndex: <string>,     ---新增加一个字段用于描述数组分裂后各个元素在原数组中的位置,此处写新增字段的名(可选参数)
      preserveNullAndEmptyArrays: <boolean>     ---默认情况下对没有此数组的行不予显示,但如果想显示则设置为true,默认是false(可选参数)
    }}
     举例说明:
数据结构如下
普通分裂之后:
 
如果还想加上后面那俩货(参数),那么:
 
6、$group
     将字段进行分组,并执行相应的操作,比如sum,max,min,但其不能排序结果集
语法:
{ $group: { _id: <expression>, <field1>: { <accumulator1> : <expression1> }, ... } }
expression1有很多选项:
可能看语法有点迷糊哦,直接上实例
数据结构:
分组:
分组并计算:
(注:count字段后面的操作可以是其他,比如max,min,push等等)

多字段分组并计算
(注:class_id,age,count的这些字段名都可以随便写哦,不要拘泥于制度)
 
在group管道符操作时,如果处理数据超过了内存限制,则会报错(如下),须使用allowDiskUse:true参数
 
7、$redact:
     这是一个非常难以理解的管道符,我算是服了,整了好久才算是明白些
     根据字段所处的document结构的级别,对文档进行适合的“修剪”,它通常和判断语句if...else结合使用,可选值有3个:
     1)$$ DESCEND:包含当前document级别的所有fields。当前级别字段的内嵌文档将会被继续检测。
     2)$$ PRUNE:不包含当前文档或者内嵌文档级别的所有字段,不会继续检测此级别的其他字段,即使这些字段的内嵌文档持有相同的访问级别。
     3)$$ KEEP:包含当前文档或内嵌文档级别的所有字段,不再继续检测此级别的其他字段,即使这些字段的内嵌文档中持有不同的访问级别。
     其实说的啥意思呢?就是某个字段符合$cond中的条件后如何处理后续字段,
     ① $$DESCEND: 符合条件后其他字段也都显示出来,并且对那些数据类型是数组或者内嵌文档的字段继续进行一样的if判断一样的处理
     ② $$PRUNE: 对符合条件的文档中所有字段全部不显示,更不会深入数组或内嵌文档汇总进行if检测
     ③$$KEEP:对符合条件的文档中同一级别的字段显示出来,但不会深入到数组或者内嵌文档的字段中进行if...else判断
举例:
     集合数据结构
     
     对age字段进行条件判断
db.t6.aggregate([
    {$redact:{
        $cond:{          ---固定格式,无需理解
            if:{$gte:["$age",20]},     ---判断条件,判断字段age>20的情况
            then:"$$DESCEND",          ---如果成立,则显示同级别的所有字段,并继续深入检测
            else:"$$PRUNE"               ---如果不成立,则同级别的所有字段全都不显示,且停止深入检测
        }
    }}
    ])
 
8、$sample:
     从上一个stage中随机选取指定数量的document
     语法:
{ $sample: { size: <positive integer> } }          ---size后面直接指定数字,代表你想选取的随机文档数量
   
 
9、$out:
     将aggregate的聚合结果集输出到指定collection中存起来,(注:$out必须放到管道符的最后一个)
     其实在我看来类似于 临时表的形式,不过咱们这个生成的是一个真实的实体集合,不会随着session的结束而删除
语法:
{ $out: "<output-collection>" }
举例:
db.t1.aggregate([
        {$sample:{size:2}},
        {$out:"random_test"}
    ])
 
10、$sort
     将结果集以某字段排序,只是排序不会改变任何document
语法:
{ $sort: { <field1>: <sort order>, <field2>: <sort order> ... } }     ---可以指定多个字段,1代表升序 -1代表降序,类似 ordery by field1 ASC ,field2 DESC
举例:
 
限制:默认,$sort阶段有100M内存的使用限制,超过此限制则会报错
 
如果想处理超过100M的数据集,则需要考虑使用 allowDiskUse选项,执行命令后会在dbpath的路径下产生一个_tmp的文件夹,用于临时存放sort的数据
注:但是allowDiskUse也不仅限于sort使用,官网解释如下:
 
11、$indexStats
     查询一个collection中每一个index的统计信息
语法:
{ $indexStats: { } }               ---写一个空{}就可以了
举例:
{
    "name" : "cdate_-1",          ---索引名
    "key" : {
        "cdate" : -1               ---索引使用的具体字段
    },
    "host" : "hostname111:27027",          ---mongod进程所在的主机名
    "accesses" : {
        "ops" : NumberLong("4"),          ---索引被访问的次数,
        "since" : ISODate("2017-07-07T02:36:58.440Z")          ---mongod开始收集index统计信息的时间
    }
},
 
注:ops 表示访问次数,但是不包括$match和mapReduce操作的访问,也不包括内部操作比如TTL索引的内部每60秒自动删除过期数据的索引访问;
     mongod重启,或者索引被删除重建后,索引的统计信息将被重置
12、$skip
     省略掉一定数量的document,其实这个命令很是简单,功能作用也都好理解,我就不过于分析解释了,相信大家都是聪明人,哈哈...
语法:
{ $skip: <positive integer> }     ---skip后面写个整数就可以了
 
13、$geoNear
     此命令主要是用于地理位置查找分析,查找距离某个位置最近和最远的点,这个目前我们也用不上,看着还挺复杂,所以偶就先不研究了,后续补充上,
 
14、$bucket:
原集合数据:
 
执行语句:
(根据price字段,按照[0,200),[200,400)范围划分组,其他范围值都为Other,之后根据分组进行计算)
groupBy: 分组字段,
boundaries: 分组范围,结果集会根据范围左边界值作为_id的值
default : 不在上述范围内的,_id 值为Other,也可定义为其他
output:进行计算,多多益善,比如计数,求和,将分组里的某字段组合成新数组
15、$autoBucket
 
16、$addFields
此管道符的意思其实就是接受上一管道符的所有字段之外,还可以额外通过表达式添加新字段,有点类似于$project,不过还是不太一样的,我们看实验。
原集合数据
>db.scores.find()
{"_id":1,"student":"Maya","homework":[10,5,10],"extraCredit":0}
{"_id":2,"student":"Ryan","homework":[5,6],"extraCredit":8}
计算homework字段的元素总和,并且与extraCredit再计算生成第二个新字段值
>db.scores.aggregate([
    {
        $addFields: {totalHomework:{$sum:"$homework"}    }
    },
    {
        $addFields: {totalScore:{$add:["$totalHomework","$extraCredit"]}}
    }
    ])
结果
{"_id":1,"student":"Maya","homework":[10,5,10],"extraCredit":0,"totalHomework":25,"totalScore":25}
{"_id":2,"student":"Ryan","homework":[5,6],"extraCredit":8,"totalHomework":11,"totalScore":19}
注:$addFields管道符可以多次使用,如果新字段的名称与现有字段相同,那么会覆盖掉现有字段的值(也包括_id);
 
17、$collStats
3.4新特性,用来显示某个集合的统计信息,返回的信息类似于db.collection.stats()命令,但更丰富些
使用如下默认格式即可
db.t1.aggregate([
    {$collStats: {
      latencyStats: { histograms: true },
      storageStats: {},
      count: {}
    }}
    ])
注:$collStats此管道符必须放到第一的位置,否则报错
 
18、$count
其实从字段意思也能看出来,就是计算文档数量,只不过是可以计算上一管道符的结果集的文档数量,其实$count的这个功能用$group+$project也能实现
注:$count之后写的是计算结果的字段名称,不能包含'$',以及点
例:
原有数据:
筛选条件后并统计
>db.t2.aggregate([
    {$match:{score:{$gte:80}}},
    {$count:"total_score"}
    ])
结果
{"total_score":4}
 
19、
 
    
 
 
 
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值