1. 程式人生 > >學習MongoDB 十一: MongoDB聚合(Aggregation Pipeline基礎篇上)(三)

學習MongoDB 十一: MongoDB聚合(Aggregation Pipeline基礎篇上)(三)

一、Aggregate簡介 

                db.collection.aggregate()是基於資料處理的聚合管道,每個文件通過一個由多個階段(stage)組成的管道,可以對每個階段的管道進行分組、過濾等功能,然後經過一系列的處理,輸出相應的結果。

               

       圖來自https://docs.mongodb.com/manual/aggregation/ 官方網

        我們通過這張圖,可以清晰的瞭解Aggregate處理的過程

         1db.collection.aggregate()可以多個管道,能方便的進行資料的處理。

         2db.collection.aggregate()使用了MongoDB內建的原生操作,聚合效率非常高,支援類似於SQL Group By操作的功能,而不再需要使用者編寫自定義的例程。

         3 每個階段管道限制為100MB記憶體。如果一個節點管道超過這個極限,MongoDB將產生一個錯誤。為了能夠在處理大型資料集,可以設定allowDiskUsetrue來在聚合管道節點把資料寫入臨時檔案。這樣就可以解決100MB記憶體的限制。

         4、db.collection.aggregate()可以作用在分片集合,但結果不能輸在分片集合,MapReduce

可以 作用在分片集合,結果也可以輸在分片集合。

    5、db.collection.aggregate()方法可以返回一個指標(cursor),資料放在記憶體中,直接操作。跟Mongo shell 一樣指標操作。

         6db.collection.aggregate()輸出的結果只能儲存在一個文件中,BSON Document大小限制為16M。可以通過返回指標解決,版本2.6中後面:DB.collect.aggregate()方法返回一個指標,可以返回任何結果集的大小。

 二、aggregate語法:

      db.collection.aggregate(pipeline, options)

     【pipeline  $group引數】

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

       $group : 將集合中的文件分組,可用於統計結果,$group首先將資料根據key進行分組。

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

          _id 是要進行分組的key

       $group:可以分組的資料執行如下的表示式計算:

           $sum:計算總和。

           $avg:計算平均值。

           $min:根據分組,獲取集合中所有文件對應值得最小值。

           $max:根據分組,獲取集合中所有文件對應值得最大值。

           $push:將指定的表示式的值新增到一個數組中。

           $addToSet:將表示式的值新增到一個集合中(無重複值)。

           $first:返回每組第一個文件,如果有排序,按照排序,如果沒有按照預設的儲存的順序的第一個文件。

           $last:返回每組最後一個文件,如果有排序,按照排序,如果沒有按照預設的儲存的順序的最後個文件。

     我們可以通過Aggregation pipeline一些使用sql用法一樣,我們能很清晰的怎麼去使用

           pipeline                                           sql

           $avg                                                 avg

           $min                                                min

           $max                                               max 

           $group                                             group by

           $sort                                               order by

           $limit                                               limit                   

           $sum                                              sum()

           $sum                                              count()

   三、pipeline $group 簡單的例子

      【資料 】 

  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. ])       

    【$group】

      1、將集合中的文件分組,可用於統計結果,$group首先將資料根據key進行分組。

             _id 是要進行分組的key,如果_idnull  相當於select  count(*) from table

  【 $sum】  

     1、 我們統計items有幾條,相當於SQL:  select count(1) as count from items

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

    2、我們統計一下數量,相當於SQL: select sum(quantity) as total  from  items

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

  3、我們通過產品型別來進行分組,然後在統計賣出的數量是多少,相當於SQL:select sum(quantity) as total from  items  group by pnumber

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

【$min 、 $max 】 

   1、我們通過相同的產品型別來進行分組,然後查詢相同產品型別賣出最多的訂單詳情 ,相當於SQL: select max(quantity) as quantity from  items  group by pnumber

  1. > db.items.aggregate([{$group:{_id:"$pnumber",max:{$max:"$quantity"}}}])  
  2. "_id" : "p001""max" : 10 }  
  3. "_id" : "p002""max" : 5 }  
  4. "_id" : "p003""max" : 10 }  

    2、我們通過相同的產品型別來進行分組,然後查詢相同產品型別賣出最多的訂單詳情 ,相當於SQL:select min(quantity) as quantity from  items  group by pnumber

  1. > db.items.aggregate([{$group:{_id:"$pnumber",min:{$min:"$quantity"}}}])  
  2. "_id" : "p001""min" : 2 }  
  3. "_id" : "p002""min" : 1 }  
  4. "_id" : "p003""min" : 2 }  

  3、我們通過相同的產品型別來進行分組,統計各個產品數量,然後獲取最大的數量,相當於SQL: select max(t.total) from (select sum(quantity) as total from  items  group by pnumber) t

  1. > db.items.aggregate([{$group:{_id:"$pnumber",total:{$sum:"$quantity"}}}])  
  2. "_id" : "p001""total" : 12 }  
  3. "_id" : "p002""total" : 8 }  
  4. "_id" : "p003""total" : 16 }  
  5. > db.items.aggregate([{$group:{_id:"$pnumber",total:{$sum:"$quantity"}}},{$group:{_id:null,max:{$max:"$total"}}}])  
  6. "_id" : null"max" : 16 }  

【$avg】

    先根據$group,在計算平均值,只會針對數字的進行計算,會對字串忽略

    1、我們通過相同的產品型別來進行分組,然後查詢每個訂單詳情相同產品型別賣出的平均價格,相當於SQL:select avg(price) as price from  items  group by pnumber

  1. > db.items.aggregate([{$group:{_id:"$pnumber",price:{$avg:"$price"}}}])  
  2. "_id" : "p001""price" : 12 }  
  3. "_id" : "p002""price" : 7.333333333333333 }  
  4. "_id" : "p003""price" : 11.666666666666666 }  

【$push】

      將指定的表示式的值新增到一個數組中,這個值不要超過16M,不然會出現錯誤

    1、我們通過相同的產品型別來進行分組,然後查詢每個相同產品賣出的數量放在數組裡面

  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 ] }  
  1. > db.items.aggregate([{$group:{_id:"$pnumber",quantitys:{$push:{quantity:"$quantity",price:"$price"}}}}])  
  2. "_id" : "p001""quantitys" : [ { "quantity" : 2, "price" : 4 }, { "quantity": 10, "price" : 20 } ] }  
  3. "_id" : "p002""quantitys" : [ { "quantity" : 2, "price" : 8 }, { "quantity": 1, "price" : 4 }, { "quantity" : 5, "price" : 10 } ] }