MongoDB聚合(Aggregation Pipeline基础篇-下)(四)

一、简介:

      上一篇我们对   db.collection.aggregate(pipeline, options)介绍,我们接下来介绍pipeline 参数和options参数的基础认识

 

  【pipeline 参数】

 

     pipeline 类型是Array  语法:db.collection.aggregate( [ { <stage> }, ... ] )

 

         $project:可以对输入文档进行添加新字段或删除现有的字段,可以自定哪些字段显示与不显示。

         $match :根据条件用于过滤数据,只输出符合条件的文档,如果放在pipeline前面,根据条件过滤数据,传输到下一个阶段管道,可以提高后续的数据处理效率。还可以放在out之前,对结果进行再一次过滤。

         $redact :字段所处的document结构的级别.

         $limit :用来限制MongoDB聚合管道返回的文档数

         $skip :在聚合管道中跳过指定数量的文档,并返回余下的文档。

         $unwind :将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。    

         $sample :随机选择从其输入指定数量的文档。如果是大于或等于5%的collection的文档,$sample进行收集扫描,进行排序,然后选择顶部的文件。因此,$sample 在收集阶段是受排序的内存限制。

                          语法:  { $sample: { size: <positive integer> } }

         $sort :将输入文档排序后输出。

         $geoNear:用于地理位置数据分析。

         $out :必须为pipeline最后一个阶段管道,因为是将最后计算结果写入到指定的collection中。

         $indexStats :返回数据集合的每个索引的使用情况。

                        语法:{ $indexStats: { } }

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

 

    我们可以通过Aggregation pipeline一些操作 跟sql用法一样,我们能很清晰的怎么去使用

 

              pipeline                                         sql

              $project                                         select

              $match                                          where

              $match(先$group阶段管道 然后在$match对统计的结果进行再一次的过滤)      having

                   $sort                                                           order by

                   $limit                                                          limit

 

 二、基础的操作

 

    【pipeline简单例子】        

        数据:   

 

[sql] view plain copy

 在CODE上查看代码片派生到我的代码片

  1. db.items.insert( [  
  2.   {  
  3.    "quantity" : 2,  
  4.    "price" : 5.0,  
  5.    "pnumber" : "p003",  
  6.   },{  
  7.    "quantity" : 2,  
  8.    "price" : 8.0,  
  9.    "pnumber" : "p002"  
  10.   },{  
  11.    "quantity" : 1,  
  12.    "price" : 4.0,  
  13.    "pnumber" : "p002"  
  14.   },{  
  15.    "quantity" : 2,  
  16.    "price" : 4.0,  
  17.    "pnumber" : "p001"  
  18.   },{  
  19.    "quantity" : 4,  
  20.    "price" : 10.0,  
  21.    "pnumber" : "p003"  
  22.   },{  
  23.    "quantity" : 10,  
  24.    "price" : 20.0,  
  25.    "pnumber" : "p001"  
  26.   },{  
  27.    "quantity" : 10,  
  28.    "price" : 20.0,  
  29.    "pnumber" : "p003"  
  30.   },{  
  31.    "quantity" : 5,  
  32.    "price" : 10.0,  
  33.    "pnumber" : "p002"  
  34.   }  
  35. ])       


 

 

 

 

 【 $project】

       1、我们对上面的统计结果,只显示count,不想_id ,可以通过$project来操作,相当SQL的select  显示我们想要的字段:

 

[sql] view plain copy

 在CODE上查看代码片派生到我的代码片

  1. > db.items.aggregate([{$group:{_id:null,count:{$sum:1}}},{$project:{"_id":0,"count":1}}])  
  2.  { "count" : 8 }  

 

 

 

 【 $match】

     1、我们想通过滤订单中,想知道卖出的数量大于8的产品有哪些产品,相当于SQL:select sum(quantity) as total from  items  group by pnumber  having total>8   

 

[sql] view plain copy

 在CODE上查看代码片派生到我的代码片

  1. > db.items.aggregate([{$group:{_id:"$pnumber",total:{$sum:"$quantity"}}},{$match:{total:{$gt:8}}}])  
  2. "_id" : "p001""total" : 12 }  
  3. "_id" : "p003""total" : 16 }  

 

 

     2、如果是放在$group之前就是当做where来使用,我们只统计pnumber =p001 产品卖出了多少个  select sum(quantity) as total from  items   where pnumber='p001'     

 

[sql] view plain copy

 在CODE上查看代码片派生到我的代码片

  1. > db.items.aggregate([{$match:{"pnumber":"p001"}},{$group:{_id:null,total:{$sum:"$quantity"}}}])  
  2. "_id" : null"total" : 12 }  

 

 

 【$skip、 $limit、$sort】

  db.items.aggregate([{ $skip: 2 },{ $limit: 4 }])     与db.items.aggregate([{ $limit: 4 },{ $skip: 2 }])  这样结果是不一样的

 

[sql] view plain copy

 在CODE上查看代码片派生到我的代码片

  1. > db.items.aggregate([{ $skip: 2 },{ $limit: 4 }])  
  2. "_id" : ObjectId("574d937cfafef57ee4427ac4"), "quantity" : 1, "price" : 4, "pnumber" : "p002" }  
  3. "_id" : ObjectId("574d937cfafef57ee4427ac5"), "quantity" : 2, "price" : 4, "pnumber" : "p001" }  
  4. "_id" : ObjectId("574d937cfafef57ee4427ac6"), "quantity" : 4, "price" : 10, "pnumber" : "p003" }  
  5. "_id" : ObjectId("574d937cfafef57ee4427ac7"), "quantity" : 10, "price" : 20, "pnumber" : "p001" }  
  6. > db.items.aggregate([{ $limit: 4 },{ $skip: 2 }])  
  7. "_id" : ObjectId("574d937cfafef57ee4427ac4"), "quantity" : 1, "price" : 4, "pnumber" : "p002" }  
  8. "_id" : ObjectId("574d937cfafef57ee4427ac5"), "quantity" : 2, "price" : 4, "pnumber" : "p001" }  
  9.    

 

 

   $limit、$skip、$sort、$match可以使用在阶段管道,如果使用在$group之前可以过滤掉一些数据,提高性能。

 

【$unwind】  

  将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。

   

[sql] view plain copy

 在CODE上查看代码片派生到我的代码片

  1. > db.items.aggregate([{$group:{_id:"$pnumber",quantitys:{$push:"$quantity"}}}])  
  2. "_id" : "p001""quantitys" : [ 2, 10 ] }  
  3. "_id" : "p002""quantitys" : [ 2, 1, 5 ] }  
  4. "_id" : "p003""quantitys" : [ 2, 4, 10 ] }  
  5. > db.items.aggregate([{$group:{_id:"$pnumber",quantitys:{$push:"$quantity"}}},{$unwind:"$quantitys"}])  
  6. "_id" : "p001""quantitys" : 2 }  
  7. "_id" : "p001""quantitys" : 10 }  
  8. "_id" : "p002""quantitys" : 2 }  
  9. "_id" : "p002""quantitys" : 1 }  
  10. "_id" : "p002""quantitys" : 5 }  
  11. "_id" : "p003""quantitys" : 2 }  
  12. "_id" : "p003""quantitys" : 4 }  
  13. "_id" : "p003""quantitys" : 10 }  

 

 

【$out】

   必须为pipeline最后一个阶段管道,因为是将最后计算结果写入到指定的collection中。

    

[sql] view plain copy

 在CODE上查看代码片派生到我的代码片

  1. "_id" : "p001""quantitys" : 2 }  
  2. "_id" : "p001""quantitys" : 10 }  
  3. "_id" : "p002""quantitys" : 2 }  
  4. "_id" : "p002""quantitys" : 1 }  
  5. "_id" : "p002""quantitys" : 5 }  
  6. "_id" : "p003""quantitys" : 2 }  
  7. "_id" : "p003""quantitys" : 4 }  
  8. "_id" : "p003""quantitys" : 10 }  

 

 

   把结果放在指定的集合中result

   

[sql] view plain copy

 在CODE上查看代码片派生到我的代码片

  1. > db.items.aggregate([{$group:{_id:"$pnumber",quantitys:{$push:"$quantity"}}},{$unwind:"$quantitys"},{$project:{"_id":0,"quantitys":1}},{$out:"result"}])  
  2. > db.result.find()  
  3. "_id" : ObjectId("57529143746e15e8aa207a29"), "quantitys" : 2 }  
  4. "_id" : ObjectId("57529143746e15e8aa207a2a"), "quantitys" : 10 }  
  5. "_id" : ObjectId("57529143746e15e8aa207a2b"), "quantitys" : 2 }  
  6. "_id" : ObjectId("57529143746e15e8aa207a2c"), "quantitys" : 1 }  
  7. "_id" : ObjectId("57529143746e15e8aa207a2d"), "quantitys" : 5 }  
  8. "_id" : ObjectId("57529143746e15e8aa207a2e"), "quantitys" : 2 }  
  9. "_id" : ObjectId("57529143746e15e8aa207a2f"), "quantitys" : 4 }  
  10. "_id" : ObjectId("57529143746e15e8aa207a30"), "quantitys" : 10 }  

 

【$redact】

     语法:{ $redact: <expression> }

   $redact 跟$cond结合使用,并在$cond里面使用了if 、then、else表达式,if-else缺一不可,$redact还有三个重要的参数:

     1)$$DESCEND: 返回包含当前document级别的所有字段,并且会继续判字段包含内嵌文档,内嵌文档的字段也会去判断是否符合条件。

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

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

 

 

  1、  level=1则值为为$$DESCEND,否则为$$PRUNE,从顶部开始扫描下去,执行$$DESCEND包含当前document级别的所有fields。当前级别字段的内嵌文档将会被继续检测。

 

[sql] view plain copy

 在CODE上查看代码片派生到我的代码片

  1. db.redact.insert(  
  2.   {  
  3.   _id: 1,  
  4.   level: 1,  
  5.   status: "A",  
  6.   acct_id: "xyz123",  
  7.   cc: [{  
  8.     level: 1,  
  9.     type: "yy",  
  10.     num: 000000000000,  
  11.     exp_date: ISODate("2015-11-01T00:00:00.000Z"),  
  12.     billing_addr: {  
  13.       level: 5,  
  14.       addr1: "123 ABC Street",  
  15.       city: "Some City"  
  16.     }  
  17.   },{  
  18.      level: 3,  
  19.     type: "yy",  
  20.     num: 000000000000,  
  21.     exp_date: ISODate("2015-11-01T00:00:00.000Z"),  
  22.     billing_addr: {  
  23.       level: 1,  
  24.       addr1: "123 ABC Street",  
  25.       city: "Some City"  
  26.     }  
  27. }]  
  28. })  
  29.    
  30. db.redact.aggregate(  
  31.   [  
  32.     { $match: { status: "A" } },  
  33.     {  
  34.       $redact: {  
  35.         $cond: {  
  36.           if: { $eq: [ "$level", 1] },  
  37.           then"$$DESCEND",  
  38.           else"$$PRUNE"  
  39.         }  
  40.       }  
  41.     }  
  42.   ]  
  43. );  
  44.   
  45. {  
  46.   "_id" : 1,  
  47.   "level" : 1,  
  48.   "status" : "A",  
  49.   "acct_id" : "xyz123",  
  50.   "cc" : [  
  51.            { "level" : 1,  
  52.      "type" : "yy",  
  53.  "num" : 0,  
  54.  "exp_date" : ISODate("2015-11-01T00:00:00Z")  
  55. }  
  56.    ]  
  57.  }  


 

 

    2、$$PRUNE:不包含当前文档或者内嵌文档级别的所有字段,不会继续检测此级别的其他字段,即使这些字段的内嵌文档持有相同的访问级别。连等级的字段都不显示,也不会去扫描等级字段包含下级。

 

 

[sql] view plain copy

 在CODE上查看代码片派生到我的代码片

  1. db.redact.insert(  
  2.   {  
  3.   _id: 1,  
  4.   level: 1,  
  5.   status: "A",  
  6.   acct_id: "xyz123",  
  7.   cc: {  
  8.     level: 3,  
  9.     type: "yy",  
  10.     num: 000000000000,  
  11.     exp_date: ISODate("2015-11-01T00:00:00.000Z"),  
  12.     billing_addr: {  
  13.       level: 1,  
  14.       addr1: "123 ABC Street",  
  15.       city: "Some City"  
  16.     }  
  17. }  
  18.  }  
  19. )  
  20. db.redact.aggregate(  
  21.   [  
  22.     { $match: { status: "A" } },  
  23.     {  
  24.       $redact: {  
  25.         $cond: {  
  26.           if: { $eq: [ "$level", 3] },  
  27.           then"$$PRUNE",  
  28.           else"$$DESCEND"  
  29.         }  
  30.       }  
  31.     }  
  32.   ]  
  33. );  
  34. "_id" : 1, "level" : 1, "status" : "A""acct_id" : "xyz123" }  

 

 

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

 

[sql] view plain copy

 在CODE上查看代码片派生到我的代码片

  1. db.redact.insert(  
  2.   {  
  3.   _id: 1,  
  4.   level: 1,  
  5.   status: "A",  
  6.   acct_id: "xyz123",  
  7.   cc: {  
  8.     level: 2,  
  9.     type: "yy",  
  10.     num: 000000000000,  
  11.     exp_date: ISODate("2015-11-01T00:00:00.000Z"),  
  12.     billing_addr: {  
  13.       level:3,  
  14.       addr1: "123 ABC Street",  
  15.       city: "Some City"  
  16.     }  
  17. }  
  18.  }  
  19. )  
  20.   
  21. db.redact.aggregate(  
  22.   [  
  23.     { $match: { status: "A" } },  
  24.     {  
  25.       $redact: {  
  26.         $cond: {  
  27.           if: { $eq: [ "$level", 1] },  
  28.           then"$$KEEP",  
  29.           else"$$PRUNE"  
  30.         }  
  31.       }  
  32.     }  
  33.   ]  
  34. );  
  35.    
  36. "_id" : 1, "level" : 1, "status" : "A""acct_id" : "xyz123""cc" : { "level" : 2, "type" : "yy""num" : 0, "exp_date" : ISODate("2015-11-01T00:00:00Z"), "billing_addr" : { "level" : 3, "addr1" : "123 ABC Street""city" : "Some City" } } }  

 

 

【 options参数】

    explain:返回指定aggregate各个阶段管道的执行计划信息。

    他操作返回一个游标,包含aggregate执行计划详细信息。

 

[sql] view plain copy

 在CODE上查看代码片派生到我的代码片

  1. db.items.aggregate([{$group:{_id:"$pnumber",total:{$sum:"$quantity"}}},{$group:{_id:null,max:{$max:"$total"}}}],{explain:true})  
  2.   
  3.   
  4.     "stages" : [  
  5.             {  
  6.                     "$cursor" : {  
  7.                             "query" : {  
  8.   
  9.                             },  
  10.                             "fields" : {  
  11.                                     "pnumber" : 1,  
  12.                                     "quantity" : 1,  
  13.                                     "_id" : 0  
  14.                             },  
  15.                             "plan" : {  
  16.                                     "cursor" : "BasicCursor",  
  17.                                     "isMultiKey" : false,  
  18.                                     "scanAndOrder" : false,  
  19.                                     "allPlans" : [  
  20.                                             {  
  21.                                                     "cursor" : "BasicCursor"  
  22.   
  23.                                                     "isMultiKey" : false,  
  24.                                                     "scanAndOrder" : false  
  25.                                             }  
  26.                                     ]  
  27.                             }  
  28.                     }  
  29.             },  
  30.             {  
  31.                     "$group" : {  
  32.                             "_id" : "$pnumber",  
  33.                             "total" : {  
  34.                                     "$sum" : "$quantity"  
  35.                             }  
  36.                     }  
  37.             },  
  38.             {  
  39.                     "$group" : {  
  40.                             "_id" : {  
  41.                                     "$const" : null  
  42.                             },  
  43.                             "max" : {  
  44.                                     "$max" : "$total"  
  45.                             }  
  46.                     }  
  47.             }  
  48.     ],  
  49.     "ok" : 1  

 

 

      allowDiskUse:每个阶段管道限制为100MB的内存,如果大于100MB的数据可以先写入临时文件。设置为true时,aggregate操作可时可以先将数据写入对应数据目录的子目录中

            的唯一并以_tmp结尾的文档中。

 

     cursor:指定游标的初始批批大小。光标的字段的值是一个与场batchSize文件。

                    语法cursor: { batchSize: <int> }

                             var cursor=db.items.aggregate([{$group:{_id:"$pnumber",total:{$sum:"$quantity"}}},{ $limit: 2 }],{cursor: { batchSize: 1 }})

                   版本2.6之后:DB.collect.aggregate()方法返回一个指针,可以返回任何结果集的大小。没有指针时返回所有的结果在一个单一的集合,并将结果集限制为16字节大小的

                  mongodb shell  设置游标大小cursor.batchSize(size) 一次返回多少条,游标提供了很多方法:

 

              cursor.hasNext()

              cursor.next()

              cursor.toArray()

              cursor.forEach()

              cursor.map()

              cursor.objsLeftInBatch()

              cursor.itcount()

              cursor.pretty()

     

     bypassDocumentValidation:只有当你指定了$out操作符,使db.collection.aggregate绕过文档验证操作过程中。这让您插入不符合验证要求的文档。

转载于:https://my.oschina.net/yagami1983/blog/887639

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值