第六章 - 數(shù)據(jù)聚合

2018-02-24 16:17 更新

聚合管道(Aggregation Pipeline)

聚合管道提供了一種方法用于轉(zhuǎn)換整合文檔到集合。你可以通過管道來(lái)傳遞文檔,就像 Unix 的 "pipe" 一樣,將一個(gè)命令的輸出傳遞到另第二個(gè),第三個(gè),等等。

最簡(jiǎn)單的聚合,應(yīng)該是你在 SQL 中早已熟悉的?group by?操作。我們已經(jīng)看過?count()?方法,那么假設(shè)我們?cè)趺床拍苤烙卸嗌倨ス?dú)角獸,有多少匹母獨(dú)角獸呢?

db.unicorns.aggregate([{$group:{_id:'$gender',
    total: {$sum:1}}}])

在 shell 中,我們有?aggregate?輔助類,用來(lái)執(zhí)行數(shù)組的管道操作。對(duì)于簡(jiǎn)單的對(duì)某物進(jìn)行分組計(jì)數(shù),我們只需要簡(jiǎn)單的調(diào)用?$group。這和 SQL 中的?GROUP BY?完全一致,我們用來(lái)創(chuàng)建一個(gè)新的文檔,以?_id?字段表示我們以什么來(lái)分組(在這里是以?gender) ,另外的字段通常被分配為聚合的結(jié)果,在這里,我們對(duì)匹配某一性別的各文檔使用了?$sum?1 。你應(yīng)該注意到了?_id?字段被分配為?'$gender'?而不是?'gender'?- 字段前面的?'$'?表示,該字段將會(huì)被輸入的文檔中的有同樣名字的值所代替,一個(gè)占位符。

我們還可以用其他什么管道操作呢?在?$group?之前(之后也很常用)的一個(gè)是?$match?- 這和?find?方法完全一樣,允許我們獲取文檔中某個(gè)匹配的子集,或者在我們的結(jié)果中對(duì)文檔進(jìn)行篩選。

db.unicorns.aggregate([{$match: {weight:{$lt:600}}},
    {$group: {_id:'$gender',  total:{$sum:1},
      avgVamp:{$avg:'$vampires'}}},
    {$sort:{avgVamp:-1}} ])

這里我們介紹另外一個(gè)管道操作?$sort?,作用和你想的完全一致,還有和它一起用的?$skip?和?$limit。以及用$group?操作?$avg。

MongoDB 數(shù)組非常強(qiáng)大,并且他們不會(huì)阻止我們往保存中的數(shù)組中寫入內(nèi)容。我們需要可以 "flatten" 他們以便對(duì)所有的東西進(jìn)行計(jì)數(shù):

db.unicorns.aggregate([{$unwind:'$loves'},
    {$group: {_id:'$loves',  total:{$sum:1},
    unicorns:{$addToSet:'$name'}}},
    {$sort:{total:-1}}, 
    {$limit:1} ])

這里我們可以找出獨(dú)角獸最喜歡吃的食物,以及拿到獨(dú)角獸們喜歡吃的食物名單。?$sort?和?$limit?的組合能讓你拿到 "top N" 這種查詢的結(jié)果。

還有另外一個(gè)強(qiáng)大的管道操作叫做?$project?(類似于?find),不但允許你拿到指定字段,還可以根據(jù)現(xiàn)存字段進(jìn)行創(chuàng)建或計(jì)算一個(gè)新字段。比如,可以用數(shù)學(xué)操作,在做平均運(yùn)算之前,對(duì)幾個(gè)字段進(jìn)行加法運(yùn)算,或者你可以用字符串操作創(chuàng)建一個(gè)新的字段,用于拼接現(xiàn)有字段。

這只是用聚合所能做到的眾多功能中的皮毛, 2.6 的聚合擁有了更強(qiáng)大的力量,比如聚合命令可以返回結(jié)果集的游標(biāo)(我們已經(jīng)在第一章學(xué)過了) 或者可以將結(jié)果寫到另外一個(gè)新集合中,通過?$out?管道操作。你可以從?MongoDB 手冊(cè)?得到關(guān)于管道操作和表達(dá)式操作更多的例子。

MapReduce

MapReduce 分兩步進(jìn)行數(shù)據(jù)處理。首先是 map,然后 reduce。在 map 步驟中,轉(zhuǎn)換輸入文檔和輸出一個(gè) key=>value 對(duì)(key 和/或 value 可以很復(fù)雜)。然后, key/value 對(duì)以 key 進(jìn)行分組,有同樣的 key 的 value 會(huì)被收入一個(gè)數(shù)組中。在 reduce 步驟中,獲取 key 和該 key 的 value 的數(shù)組,生成最終結(jié)果。map 和 reduce 方法用 JavaScript 來(lái)編寫。

在 MongoDB 中我們對(duì)一個(gè)集合使用?mapReduce?命令。?mapReduce?執(zhí)行 map 方法, reduce 方法和 output 指令。在我們的 shell 中,我們可以創(chuàng)建輸入一個(gè) JavaScript 方法。許多庫(kù)中,支持字符串方法 (有點(diǎn)丑)。第三個(gè)參數(shù)設(shè)置一個(gè)附加參數(shù),比如說(shuō)我們可以過濾,排序和限制那些我們想要分析的文檔。我們也可以提供一個(gè)?finalize?方法來(lái)處理?reduce?步驟之后的結(jié)果。

在你的大多數(shù)聚合中,也許無(wú)需用到 MapReduce , 但如果需要,你可以讀到更多關(guān)于它的內(nèi)容,從?我的 blog?和?MongoDB 手冊(cè)。

小結(jié)

在這章中我們介紹了 MongoDB 的?聚合功能(aggregation capabilities)。 一旦你理解了聚合管道(Aggregation Pipeline)的構(gòu)造,它還是相對(duì)容易編寫的,并且它是一個(gè)聚合數(shù)據(jù)的強(qiáng)有力工具。 MapReduce 更難理解一點(diǎn),不過它強(qiáng)力無(wú)邊,就像你用 JavaScript 寫的代碼一樣。

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)