MongoDB中的數據聚合工具Aggregate和Group

周煦辰 2016-01-16

來講說MongoDB中的數據聚合工具。javascript

Aggregate是MongoDB提供的衆多工具中的比較重要的一個,相似於SQL語句中的GROUP BY。聚合工具可讓開發人員直接使用MongoDB原生的命令操做數據庫中的數據,而且按照要求進行聚合。聚合不只極大提高了開發的效率,更重要的是,原生的工具運行效率比本身寫聚合的方法高到不知道哪裏去了。
下面簡單說一下PHP開發環境下如何使用MongoDB的數據聚合工具 Aggregation Pipleline和Group。其實PHP下的MongoDB使用和原生差很少,無非是語法從JavaScript變成了PHP而已,大體的操做流程是差很少,命令的格式也是很是相像的。基本上只要會看MongoDB的文檔,就能經過PHP操做MongoDB了。php

Aggregation Pipleline

關於Aggregation,官方文檔在這裏。我這裏就半翻譯半扯淡(固然大部分是扯淡)說一下Aggregation Pipleline。java

管道的概念

管道在*nix中將上一個命令輸出的數據做爲下一個命令的參數。MongoDB中的管道操做是能夠重複的,基於這個概念,MongoDB中的管道聚合能夠有很是實用的玩法,好比對聚合的結果進行排序mongodb

那麼,如何使用呢

img

借用一下官方的圖,這裏aggregate的命令爲:數據庫

[
    {$match: {status: "A"}},
    {$group: {_id: "$cust_id", total: {$sum: "$amount"}}}
]

aggreagte是一個數組,其中包含多個對象(命令),經過遍歷Pipleline數組對collection中的數據進行操做。
解釋一下例子中的配置項意思。數組

$match:查詢條件函數

  • 常用正則表示的人確定對match不陌生,很明顯$match是配置查詢數據時的條件。這裏的語法和查詢數據庫的時候一毛同樣,也就再也不贅述了,看一下MongoDB的CRUD文檔便可。

$group:聚合的配置工具

  • _id表明你想聚合的數據的主鍵,例如上述數據中,你想聚合全部cust_id相同的條目的amount的總和,那_id即被設置爲cust_id_id必須,可是你能夠填寫一個空值。
  • total表明你最後想輸出的數據之一,這裏total是每條結果中amount的總和。
  • $sum是一個聚合的操做符,另外的操做符你能夠在官方文檔中找到。上圖中的命令表示對相同主鍵(_id)下的amount進行求和。若是你想要計算主鍵出現的次數,能夠把命令寫成以下的形式
{$sum: 1}

聚合的過程

看一下圖例,全部的數據先通過$match命令,只留下了status爲A的數據,接着,對篩選出的數據進行聚合操做,對相同cust_id的數據進行計算amount總和的操做,最後輸出結果。性能

其餘管道表達式與操做符

其餘的管道表達式操做符均可以在官方文檔中找到。優化

這裏說一下$sort操做符。前面說過,利用管道的特性,能夠作到對結果進行排序。因此只須要在$group操做以後使用$sort操做便可,這點在報表的製做上十分實用。何況使用MongoDB對結果進行排序也能夠儘可能優化性能。

Group

MongoDB另外一個重要的聚合工具就是Group,所不一樣的是,Aggregate操做中,傳入的Pipleline是一個包含多個對象的數組,每個對象表明了一個命令。而Group有傳入的命令中共有六個參數,其中三個……是JavaScript函數,所以每次查詢到匹配的數據,都會被轉換爲對象傳入函數。從運行效率上來講,Group確定比Aggregate差一大截。可是Group的優點在於靈活,由於配置項能夠經過本身編寫函數來實現。可是須要注意的是,儘管這樣作看起來很是靈活方便,可是一旦函數複雜度過大,將大大影響Group的性能,所以箇中取捨還須要本身定奪。

那麼,怎麼用呢

從我我的來講,用得最多的是keycond$reduceinital這四個命令。

使用上面Aggregation Pipleline中的數據爲例。

  • key:其實和上邊說的Aggregation Pipleline中的_id是同樣的。假設這裏是{cust_id: 1}
  • cond:和上邊說的$match是同樣的。
  • $reduce:一個函數,對匹配到的數據進行操做,這個放在後面說。
  • initial:初始數據,假設咱們這裏是{count: 0}

$reduce

function(obj, prev) {
    prev.count += obj.amount;
}

$reduce的函數(仍是匿名的)能夠傳入兩個參數,第一個是被轉換爲對象的條目,第二個是被實例化的initial對象。
最後的結果和Aggregate操做的同樣:

{
    retval: [
        {
            cust_id: "A123",
            count: 750
        },
        {
            cust_id: "B212",
            count: 200
        }
    ],
    count: 3,
    keys: 2,
    ok: 1
}

那麼,PHP裏面應該怎麼用呢

PHP中的Mongo操做和原生的使用JavaScript操做很是像。例如第一個例子的代碼以下:

<?php 
$mongo      = new MongoClient(DB_CONNECT);
$db         = $mongo->db;
$collection = $db->selectCollection('orders');

$pipleline  = array(
    array(
        '$match' => array(
            'status' => array(
                '$eq' => 'A',
            ),
        ),
    ),
    array(
        '$group' => array(
            '_id'   => '$cust_id',
            'total' => array(
                '$sum' => '$amount',
            ),
        ),
    ),
);

$a = $collection->aggregate($pipleline);
$result = isset($a['result']) ? $a['result'] : array();

第二個例子的代碼以下

<?php 
$mongo      = new MongoClient(DB_CONNECT);
$db         = $mongo->db;
$collection = $db->selectCollection('orders');

$keys    = array('cust_id' => 1);
$initial = array('count' => 0);
$reduce  = 'function(obj, prev) {prev.count += obj.amount;}';
$cond    = array('condition' => array('status' => 'A'));

$g = $collection->group($keys, $initial, $reduce, $cond);
$retval = isset($g['retval']) ? $g['retval'] : array();

其餘的功能,須要本身多參考PHP官方文檔和Mongo的文檔進行嘗試了。

相關文章
相關標籤/搜索