## 聚合管道(Aggregation Pipeline)
聚合管道提供了一種方法用于轉換整合文檔到集合。你可以通過管道來傳遞文檔,就像 Unix 的 "pipe" 一樣,將一個命令的輸出傳遞到另第二個,第三個,等等。
最簡單的聚合,應該是你在 SQL 中早已熟悉的?`group by`?操作。我們已經看過?`count()`?方法,那么假設我們怎么才能知道有多少匹公獨角獸,有多少匹母獨角獸呢?
~~~
db.unicorns.aggregate([{$group:{_id:'$gender',
total: {$sum:1}}}])
~~~
在 shell 中,我們有?`aggregate`?輔助類,用來執行數組的管道操作。對于簡單的對某物進行分組計數,我們只需要簡單的調用?`$group`。這和 SQL 中的?`GROUP BY`?完全一致,我們用來創建一個新的文檔,以?`_id`?字段表示我們以什么來分組(在這里是以?`gender`) ,另外的字段通常被分配為聚合的結果,在這里,我們對匹配某一性別的各文檔使用了?`$sum`?1 。你應該注意到了?`_id`?字段被分配為?`'$gender'`?而不是?`'gender'`?- 字段前面的?`'$'`?表示,該字段將會被輸入的文檔中的有同樣名字的值所代替,一個占位符。
我們還可以用其他什么管道操作呢?在?`$group`?之前(之后也很常用)的一個是?`$match`?- 這和?`find`?方法完全一樣,允許我們獲取文檔中某個匹配的子集,或者在我們的結果中對文檔進行篩選。
~~~
db.unicorns.aggregate([{$match: {weight:{$lt:600}}},
{$group: {_id:'$gender', total:{$sum:1},
avgVamp:{$avg:'$vampires'}}},
{$sort:{avgVamp:-1}} ])
~~~
這里我們介紹另外一個管道操作?`$sort`?,作用和你想的完全一致,還有和它一起用的?`$skip`?和?`$limit`。以及用`$group`?操作?`$avg`。
MongoDB 數組非常強大,并且他們不會阻止我們往保存中的數組中寫入內容。我們需要可以 "flatten" 他們以便對所有的東西進行計數:
~~~
db.unicorns.aggregate([{$unwind:'$loves'},
{$group: {_id:'$loves', total:{$sum:1},
unicorns:{$addToSet:'$name'}}},
{$sort:{total:-1}},
{$limit:1} ])
~~~
這里我們可以找出獨角獸最喜歡吃的食物,以及拿到獨角獸們喜歡吃的食物名單。?`$sort`?和?`$limit`?的組合能讓你拿到 "top N" 這種查詢的結果。
還有另外一個強大的管道操作叫做?[`$project`](http://docs.mongodb.org/manual/reference/operator/aggregation/project/#pipe._S_project)?(類似于?`find`),不但允許你拿到指定字段,還可以根據現存字段進行創建或計算一個新字段。比如,可以用數學操作,在做平均運算之前,對幾個字段進行加法運算,或者你可以用字符串操作創建一個新的字段,用于拼接現有字段。
這只是用聚合所能做到的眾多功能中的皮毛, 2.6 的聚合擁有了更強大的力量,比如聚合命令可以返回結果集的游標(我們已經在第一章學過了) 或者可以將結果寫到另外一個新集合中,通過?`$out`?管道操作。你可以從?[MongoDB 手冊](http://docs.mongodb.org/manual/core/aggregation-pipeline/)?得到關于管道操作和表達式操作更多的例子。
## [](https://github.com/geminiyellow/the-little-mongodb-book/blob/master/zh-cn/mongodb.markdown#mapreduce)MapReduce
MapReduce 分兩步進行數據處理。首先是 map,然后 reduce。在 map 步驟中,轉換輸入文檔和輸出一個 key=>value 對(key 和/或 value 可以很復雜)。然后, key/value 對以 key 進行分組,有同樣的 key 的 value 會被收入一個數組中。在 reduce 步驟中,獲取 key 和該 key 的 value 的數組,生成最終結果。map 和 reduce 方法用 JavaScript 來編寫。
在 MongoDB 中我們對一個集合使用?`mapReduce`?命令。?`mapReduce`?執行 map 方法, reduce 方法和 output 指令。在我們的 shell 中,我們可以創建輸入一個 JavaScript 方法。許多庫中,支持字符串方法 (有點丑)。第三個參數設置一個附加參數,比如說我們可以過濾,排序和限制那些我們想要分析的文檔。我們也可以提供一個?`finalize`?方法來處理?`reduce`?步驟之后的結果。
在你的大多數聚合中,也許無需用到 MapReduce , 但如果需要,你可以讀到更多關于它的內容,從?[我的 blog](http://openmymind.net/2011/1/20/Understanding-Map-Reduce/)?和?[MongoDB 手冊](http://docs.mongodb.org/manual/core/map-reduce/)。
## [](https://github.com/geminiyellow/the-little-mongodb-book/blob/master/zh-cn/mongodb.markdown#小結-5)小結
在這章中我們介紹了 MongoDB 的?[聚合功能(aggregation capabilities)](http://docs.mongodb.org/manual/aggregation/)。 一旦你理解了聚合管道(Aggregation Pipeline)的構造,它還是相對容易編寫的,并且它是一個聚合數據的強有力工具。 MapReduce 更難理解一點,不過它強力無邊,就像你用 JavaScript 寫的代碼一樣。