MongoDB聚合(二) 2.3 $group $group操做能夠將文檔根據給定字段的不一樣值進行分組。 若是選定了須要分組的字段,能夠將選定的字段傳遞給"$group"函數的"_id"字段。 { "$group" : {"_id" : "$day"} } { "$group" : {"_id" : "$grade"} } { "$group" : {"_id" : {"state" : "$state", "city" : "$city"}} } 2.3.1 分組操做符 容許對每一個分組進行計算,獲得相應的結果。 2.3.2 算術操做符 兩個操做符用於對數值類型的字段的值進行計算:"$sum"和"$average"。 "$sum",對於分組中的每一個文檔,將value與計算結果相加。 例如: 插入測試數據: countrys = ["china", "japan", "germany", "canada", "india"] for (var i = 1; i < 100; i ++) { name = countrys[Math.floor(Math.random() * countrys.length)] money = Math.floor(1000 * Math.random()) db.foo.insert({"country" : name, "_id" : i, "money" : money}) } 分組: db.foo.aggregate( { "$group" : { "_id" : "$country", "total" : {"$sum" : "$money"} } }) 返回結果: { "_id" : "canada", "total" : 11316 } { "_id" : "china", "total" : 7225 } { "_id" : "india", "total" : 11190 } { "_id" : "germany", "total" : 10288 } { "_id" : "japan", "total" : 9330 } $avg,返回每一個分組的平均值。 例如: 聚合: db.foo.aggregate( { "$group" : { "_id" : "$country", "average" : {"$avg" : "$money"} } }) 返回結果: { "_id" : "canada", "average" : 595.578947368421 } { "_id" : "china", "average" : 481.6666666666667 } { "_id" : "india", "average" : 559.5 } { "_id" : "germany", "average" : 411.52 } { "_id" : "japan", "average" : 466.5 } 2.3.3 極值操做符 極值操做符獲取數據集合的邊緣值。 "$max" : expr 返回最大值。 "$min" : expr 返回最小值。 "$first" : expr 返回分組第一個值。 "$last" : expr 返回分組最後一個值。 "$max"和"$min"會查看文檔沒一個值。 例如: db.foo.aggregate( { "$group" : { "_id" : "$country", "lowest" : {"$min" : "$money"}, "highest" : {"$max" : "$money"}, } }) 返回結果: { "_id" : "canada", "lowest" : 130, "highest" : 950 } { "_id" : "china", "lowest" : 15, "highest" : 949 } { "_id" : "india", "lowest" : 98, "highest" : 994 } { "_id" : "germany", "lowest" : 36, "highest" : 960 } { "_id" : "japan", "lowest" : 28, "highest" : 850 } 若是結果集是有序的,則使用"$first"和"$last"操做。 例如: 插入測試數據: for (var i = 1; i < 100; i++) { name = "caoqing", age = i db.foo1.insert({"name" : name, "age" : age}) } 聚合: db.foo1.aggregate( { "$group" : { "_id" : "$name", "lowest" : {"$first" : "$age"}, "highest" : {"$last" : "$age"}, } } ) 查詢結果: { "_id" : "caoqing", "lowest" : 1, "highest" : 99 } 2.3.4 數組操做符 對數組進行操做。 "$addToSet" : expr 若是當前數組不包含expr,則添加。返回結果集中,每一個元素最多出現一次。 "$push" : expr 添加expr到數組,返回包含全部值的數組。 2.3.5 分組行爲 大多數操做符都是流式工做的,只要有新文檔進入,就能夠處理,可是"$group"必須等到收入全部文檔後,才能分組,而後將分組發送給管道中的下一操做符。 在分片狀況下,"$group"先在每一個分片上執行,而後把分組結果發送到mongos再進行統一分組,剩餘的管道操做也都是在mongos上運行的。 2.4 $unwind 拆分能夠將數組的每個值拆分爲單獨的文檔。 例如: db.blog.insert({ "auther" : "caoqing", "comments" : [ { "CEO" : "Bill Gates", "corp" : "MicroSoft" }, { "CEO" : "Mark Zuckerberg", "corp" : "Facebook" }, { "CEO" : "Dick Costolo", "corp" : "Twitter" } ] }) 拆分: db.blog.aggregate( { "$unwind" : "$comments" }) 結果: { "_id" : ObjectId("5360c4f909e603f892b1457c"), "auther" : "caoqing", "comments" : { "CEO" : "Bill Gates", "corp" : "MicroSoft" } } { "_id" : ObjectId("5360c4f909e603f892b1457c"), "auther" : "caoqing", "comments" : { "CEO" : "Mark Zuckerberg", "corp" : "Facebook" } } { "_id" : ObjectId("5360c4f909e603f892b1457c"), "auther" : "caoqing", "comments" : { "CEO" : "Dick Costolo", "corp" : "Twitter" } } 若是但願獲得特定的子文檔,能夠先拆分,再"$match"獲得結果。 db.blog.aggregate( { "$project" : {"comments" : "$comments"}}, {"$unwind" : "$comments"}, {"$match" : {"comments.CEO" : "Mark Zuckerberg"}} ) 結果: { "_id" : ObjectId("5360c4f909e603f892b1457c"), "comments" : { "CEO" : "Mark Zuckerberg", "corp" : "Facebook" } } 2.5 $sort 能夠根據任意字段或多個字段進行排序。若是須要大量排序,最好在管道的第一階段進行排序,這時可使用索引。不然排序會很慢,佔用大量內存。 例如: db.foo.aggregate( { "$group" : { "_id" : "$country", "total" : {"$sum" : "$money"} }}, {"$sort" : {"total" : -1, "country" : 1}} ) 結果: { "_id" : "canada", "total" : 11316 } { "_id" : "india", "total" : 11190 } { "_id" : "germany", "total" : 10288 } { "_id" : "japan", "total" : 9330 } { "_id" : "china", "total" : 7225 } 2.6 $limit $limit接受一個參數n,返回結果集中前n個文檔。 例如: db.foo.aggregate( { "$group" : { "_id" : "$country", "total" : {"$sum" : "$money"} }}, {"$sort" : {"total" : -1, "country" : 1}}, {"$limit" : 3} ) 結果: { "_id" : "canada", "total" : 11316 } { "_id" : "india", "total" : 11190 } { "_id" : "germany", "total" : 10288 } 2.7 $skip $skip接受一個參數n,丟棄結果集中前n個文檔,將剩餘文檔返回。若是須要丟棄大量數據,效率會很低。 例如: db.foo.aggregate( { "$group" : { "_id" : "$country", "total" : {"$sum" : "$money"} }}, {"$sort" : {"total" : -1, "country" : 1}}, {"$skip" : 2} ) 結果: { "_id" : "germany", "total" : 10288 } { "_id" : "japan", "total" : 9330 } { "_id" : "china", "total" : 7225 } 2.8 使用管道 應該在管道開始階段(執行"$project", "$group", "$unwind"操做前)將盡量多的文檔和字段過濾掉,管道若是不是直接從原來的集合中使用數據,就沒法在篩選和排序過程當中使用索引。 Mongodb不容許單一的聚合操做佔用過多的內存,若是某個操做佔用20%以上內存,操做會直接輸出錯誤。 能夠將結果集放入一個集合方便之後調用。