概述:



众所周知,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;这样可以进行更细化的数据处理



数据集合




mongodb OplogReplay参数 mongodb lookup pipeline_数组


 


使用方法详述


下面就简单介绍一下各个组件的使用方法:


1、$project:


     遍历文档的指定字段到下一个stage(阶段);


     意思就是说可以过滤掉某些字段(包括过滤掉_id)、可以重命名字段、添加新的字段,重置字段的值


     语法:


{ $project: { <specifications> } }     


     


<specifications>的选项

描述

<field>:  <1  or  true>

执行显示哪些字段

_id:  <0  or  false>

过滤掉_id字段

<field>:  <expression>

添加新字段或者重置字段的值

     举例:


     

mongodb OplogReplay参数 mongodb lookup pipeline_数据_02


2、$match:


     查询需要的数据给到下一个stage;


     如果放到aggregate开端的话,可以利用上索引,与find()中的query语法一致


     语法:


{ $match: { <query> } }     ---query中写什么呢?就是在find()中写的东东


     举例:


mongodb OplogReplay参数 mongodb lookup pipeline_数据_03


3、$limit:


     其实就是做一个行数的限制,类似top 10 *


     语法:


{ $limit: <positive integer> }


     举例:


mongodb OplogReplay参数 mongodb lookup pipeline_数据_04


 


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是什么?那就继续向下看吧


     举例:


     

mongodb OplogReplay参数 mongodb lookup pipeline_数组_05


5、$unwind:


     分裂数组,重组数据(document)


语法:


{
     
  $unwind:
     
    {
     
      path: <field path>,     ---你想要分裂的数组名称
     
      includeArrayIndex: <string>,     ---新增加一个字段用于描述数组分裂后各个元素在原数组中的位置,此处写新增字段的名(可选参数)
     
      preserveNullAndEmptyArrays: <boolean>     ---默认情况下对没有此数组的行不予显示,但如果想显示则设置为true,默认是false(可选参数)
     
    }}


     举例说明:


数据结构如下


mongodb OplogReplay参数 mongodb lookup pipeline_数据_06


普通分裂之后:


mongodb OplogReplay参数 mongodb lookup pipeline_字段_07


 


如果还想加上后面那俩货(参数),那么:


mongodb OplogReplay参数 mongodb lookup pipeline_数据_08


 


6、$group


     将字段进行分组,并执行相应的操作,比如sum,max,min,但其不能排序结果集


语法:


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


expression1有很多选项:


$sum     


$avg


$first


$last


$max


$min


$push


$addToSet


$stdDevPop


$stdDevSamp


可能看语法有点迷糊哦,直接上实例


数据结构:


mongodb OplogReplay参数 mongodb lookup pipeline_数组_09


分组:


mongodb OplogReplay参数 mongodb lookup pipeline_数组_10


分组并计算:


(注:count字段后面的操作可以是其他,比如max,min,push等等)




mongodb OplogReplay参数 mongodb lookup pipeline_字段_11


多字段分组并计算


(注:class_id,age,count的这些字段名都可以随便写哦,不要拘泥于制度)


mongodb OplogReplay参数 mongodb lookup pipeline_数据_12


 


在group管道符操作时,如果处理数据超过了内存限制,则会报错(如下),须使用allowDiskUse:true参数


mongodb OplogReplay参数 mongodb lookup pipeline_字段_13


 


7、$redact:


     这是一个非常难以理解的管道符,我算是服了,整了好久才算是明白些


     根据字段所处的document结构的级别,对文档进行适合的“修剪”,它通常和判断语句if...else结合使用,可选值有3个:


     1)$$ DESCEND:包含当前document级别的所有fields。当前级别字段的内嵌文档将会被继续检测。


     2)$$ PRUNE:不包含当前文档或者内嵌文档级别的所有字段,不会继续检测此级别的其他字段,即使这些字段的内嵌文档持有相同的访问级别。


     3)$$ KEEP:包含当前文档或内嵌文档级别的所有字段,不再继续检测此级别的其他字段,即使这些字段的内嵌文档中持有不同的访问级别。


     其实说的啥意思呢?就是某个字段符合$cond中的条件后如何处理后续字段,


     ① $$DESCEND: 符合条件后其他字段也都显示出来,并且对那些数据类型是数组或者内嵌文档的字段继续进行一样的if判断一样的处理


     ② $$PRUNE: 对符合条件的文档中所有字段全部不显示,更不会深入数组或内嵌文档汇总进行if检测


     ③$$KEEP:对符合条件的文档中同一级别的字段显示出来,但不会深入到数组或者内嵌文档的字段中进行if...else判断


举例:


     集合数据结构


     

mongodb OplogReplay参数 mongodb lookup pipeline_数组_14


     对age字段进行条件判断


db.t6.aggregate([


    {$redact:{


        $cond:{          ---固定格式,无需理解


            if:{$gte:["$age",20]},     ---判断条件,判断字段age>20的情况


            then:"$$DESCEND",          ---如果成立,则显示同级别的所有字段,并继续深入检测


            else:"$$PRUNE"               ---如果不成立,则同级别的所有字段全都不显示,且停止深入检测


        }


    }}


    ])


mongodb OplogReplay参数 mongodb lookup pipeline_数组_15


 


8、$sample:


     从上一个stage中随机选取指定数量的document


     语法:


{ $sample: { size: <positive integer> } }          ---size后面直接指定数字,代表你想选取的随机文档数量


   

mongodb OplogReplay参数 mongodb lookup pipeline_字段_16


 


9、$out:


     将aggregate的聚合结果集输出到指定collection中存起来,(注:$out必须放到管道符的最后一个)


     其实在我看来类似于 临时表的形式,不过咱们这个生成的是一个真实的实体集合,不会随着session的结束而删除


语法:


{ $out: "<output-collection>" }


举例:


db.t1.aggregate([


        {$sample:{size:2}},


        {$out:"random_test"}


    ])


mongodb OplogReplay参数 mongodb lookup pipeline_数据_17


 


10、$sort


     将结果集以某字段排序,只是排序不会改变任何document


语法:


{ $sort: { <field1>: <sort order>, <field2>: <sort order> ... } }     ---可以指定多个字段,1代表升序 -1代表降序,类似 ordery by field1 ASC ,field2 DESC


举例:


mongodb OplogReplay参数 mongodb lookup pipeline_数据_18


 


限制:默认,$sort阶段有100M内存的使用限制,超过此限制则会报错


mongodb OplogReplay参数 mongodb lookup pipeline_数组_19


 


allowDiskUse选项,执行命令后会在dbpath的路径下产生一个_tmp的文件夹,用于临时存放sort的数据


mongodb OplogReplay参数 mongodb lookup pipeline_数据_20


注:但是allowDiskUse也不仅限于sort使用,官网解释如下:


mongodb OplogReplay参数 mongodb lookup pipeline_字段_21


 


11、$indexStats


     查询一个collection中每一个index的统计信息


语法:


{ $indexStats: { } }               ---写一个空{}就可以了


举例:


mongodb OplogReplay参数 mongodb lookup pipeline_数组_22


{


    "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:


原集合数据:


mongodb OplogReplay参数 mongodb lookup pipeline_字段_23


 


执行语句:


(根据price字段,按照[0,200),[200,400)范围划分组,其他范围值都为Other,之后根据分组进行计算)


groupBy: 分组字段,


boundaries: 分组范围,结果集会根据范围左边界值作为_id的值


default : 不在上述范围内的,_id 值为Other,也可定义为其他


output:进行计算,多多益善,比如计数,求和,将分组里的某字段组合成新数组


mongodb OplogReplay参数 mongodb lookup pipeline_数据_24


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}


mongodb OplogReplay参数 mongodb lookup pipeline_数组_25


注:$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之后写的是计算结果的字段名称,不能包含'$',以及点


例:


原有数据:


mongodb OplogReplay参数 mongodb lookup pipeline_数据_26


筛选条件后并统计


>db.t2.aggregate([
    
    {$match:{score:{$gte:80}}},
    
    {$count:"total_score"}
    
    ])


结果


{"total_score":4}


mongodb OplogReplay参数 mongodb lookup pipeline_字段_27


 


19、