天天看點

Mongodb聚合查詢介紹

一,mongodb聚合介紹

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

通過這張圖,可以了解Aggregate處理的過程。

Mongodb聚合查詢介紹

1、db.collection.aggregate() 可以用多個構件建立一個管道,對于一連串的文檔進行處理。這些構件包括:篩選操作的match、映射操作的project、分組操作的group、排序操作的sort、限制操作的limit、和跳過操作的skip。

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

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

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

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

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

二,mongodb和mysql的聚合的參照

為了便于了解,先将常見的mongo的聚合操作和mysql的查詢做下類比:

Mongodb聚合查詢介紹

下面舉了一些常用的mongo聚合例子和mysql對比,假設有一條如下的資料庫記錄(表名:orders)作為例子:

{
  cust_id: "abc123",
  ord_date: ISODate("2012-11-02T17:04:11.102Z"),
  status: 'A',
  price: 50,
  items: [ { sku: "xxx", qty: 25, price: 1 },
           { sku: "yyy", qty: 25, price: 1 } ]
}
           

1. 統計orders表所有記錄

db.orders.aggregate( [
   {
     $group: {
        _id: null,
        count: { $sum: 1 }
     }
   }
] )

類似mysql:
SELECT COUNT(*) AS count   FROM orders
           

2.對orders表計算所有price求和

db.orders.aggregate( [
   {
     $group: {
        _id: null,
        total: { $sum: "$price" }
     }
   }
] )

類似mysql;
SELECT SUM(price) AS total  FROM orders
           

3.對每一個唯一的cust_id, 計算price總和

db.orders.aggregate( [
   {
     $group: {
        _id: "$cust_id",
        total: { $sum: "$price" }
     }
   }
] )

類似mysql:
SELECT cust_id,
       SUM(price) AS total
FROM orders
GROUP BY cust_id
           

4.對每一個唯一對cust_id和ord_date分組,計算price總和,不包括日期的時間部分

db.orders.aggregate( [
   {
     $group: {
        _id: {
           cust_id: "$cust_id",
           ord_date: {
               month: { $month: "$ord_date" },
               day: { $dayOfMonth: "$ord_date" },
               year: { $year: "$ord_date"}
           }
        },
        total: { $sum: "$price" }
     }
   }
] )

類似mysql:
SELECT cust_id,
       ord_date,
       SUM(price) AS total
FROM orders
GROUP BY cust_id,
         ord_date
           

5.對于有多個記錄的cust_id,傳回cust_id和對應的數量

db.orders.aggregate( [
   {
     $group: {
        _id: "$cust_id",
        count: { $sum: 1 }
     }
   },
   { $match: { count: { $gt: 1 } } }
] )

類似mysql:
SELECT cust_id,
       count(*)
FROM orders
GROUP BY cust_id
HAVING count(*) > 1
           

6.對每個唯一的cust_id和ord_date分組,計算價格總和,并隻傳回price總和大于250的記錄,且排除日期的時間部分

db.orders.aggregate( [
   {
     $group: {
        _id: {
           cust_id: "$cust_id",
           ord_date: {
               month: { $month: "$ord_date" },
               day: { $dayOfMonth: "$ord_date" },
               year: { $year: "$ord_date"}
           }
        },
        total: { $sum: "$price" }
     }
   },
   { $match: { total: { $gt: 250 } } }
] )

類似mysql:
SELECT cust_id,
       ord_date,
       SUM(price) AS total
FROM orders
GROUP BY cust_id,
         ord_date
HAVING total > 250
           

7.對每個唯一的cust_id且status=A,計算price總和

db.orders.aggregate( [
   { $match: { status: 'A' } },
   {
     $group: {
        _id: "$cust_id",
        total: { $sum: "$price" }
     }
   }
] )

類似mysql:
SELECT cust_id,
       SUM(price) as total
FROM orders
WHERE status = 'A'
GROUP BY cust_id
           

8.對每個唯一的cust_id且status=A,計算price總和并且隻傳回price總和大于250的記錄

db.orders.aggregate( [
   { $match: { status: 'A' } },
   {
     $group: {
        _id: "$cust_id",
        total: { $sum: "$price" }
     }
   },
   { $match: { total: { $gt: 250 } } }
] )

類似mysql:

SELECT cust_id,
       SUM(price) as total
FROM orders
WHERE status = 'A'
GROUP BY cust_id
HAVING total > 250
           

9.對于每個唯一的cust_id,将與orders相關聯的相應訂單項order_lineitem的qty字段進行總計

db.orders.aggregate( [
   { $unwind: "$items" },
   {
     $group: {
        _id: "$cust_id",
        qty: { $sum: "$items.qty" }
     }
   }
] )

類似mysql:
SELECT cust_id,
       SUM(li.qty) as qty
FROM orders o,
     order_lineitem li
WHERE li.order_id = o.id
GROUP BY cust_id
           

10.統計不同cust_id和ord_date分組的數量,排除日期的時間部分

db.orders.aggregate( [
   {
     $group: {
        _id: {
           cust_id: "$cust_id",
           ord_date: {
               month: { $month: "$ord_date" },
               day: { $dayOfMonth: "$ord_date" },
               year: { $year: "$ord_date"}
           }
        }
     }
   },
   {
     $group: {
        _id: null,
        count: { $sum: 1 }
     }
   }
] )

類似mysql:
SELECT COUNT(*)
FROM (SELECT cust_id, ord_date
      FROM orders
      GROUP BY cust_id, ord_date)
      as DerivedTable