MongoDB學習【二】MongoDB高級聚合查詢詳解

MongoDB高級聚合查詢詳解

一、聚合的基本概念

聚合操作可處理數據記錄並返回計算結果。聚合操作將來自多個文檔的值組合在一起,並且可以對分組的數據執行各種操作以返回單個結果。官方圖解如下:參考地址 https://docs.mongodb.com/manual/aggregation/

//聚合基本命令
db.orders.aggregate([
   { $match: { status: "A" } },
   { $group: { _id: "$cust_id", total: { $sum: "$amount" } } }
])

第一階段$match階段,按status字段過濾文檔,並將status="A"的文檔傳遞到下一階段。

第二階段$group階段,按cust_id字段將文檔分組,並計算每個唯一cust_id文檔amount值的總和。

最基本的管道階段提供過濾器,其操作類似於查詢和修改輸出文檔形式的文檔轉換

其他管道操作提供了用於按特定字段對文檔進行分組和排序的工具,以及用於聚合包括文檔數組在內的數組內容的工具。另外,管道階段可以將運算符用於諸如計算平均值或連接字符串之類的任務。

二、聚合的階段Stage

//聚合命令基本格式:所有的階段除$out,$merge和$geoNear階段以外都可以在管道中出現多次。
db.collection.aggregate( [ { <stage> }, ... ] )

重點記錄一下常用的幾個,以後用到再補充。先給我們的數據庫造一波測試數據,數據量12000,表示:用戶id、年級、班級、科目、得分、時間。然後開始我們的聚合學習之路~~~

{ "_id" : ObjectId("5eeb0c2d4d057134880073b2"), "uid" : "uid1", "grade" : 3, "class" : 5, "subject" : "math", "score" : 50, "createTime" : 1592462381 }
{ "_id" : ObjectId("5eeb0c2d4d057134880073b3"), "uid" : "uid1", "grade" : 3, "class" : 5, "subject" : "chinese", "score" : 94, "createTime" : 1592462381 }
{ "_id" : ObjectId("5eeb0c2d4d057134880073b4"), "uid" : "uid1", "grade" : 3, "class" : 5, "subject" : "english", "score" : 7, "createTime" : 1592462381 }
{ "_id" : ObjectId("5eeb0c2d4d057134880073b5"), "uid" : "uid1", "grade" : 3, "class" : 5, "subject" : "science", "score" : 6, "createTime" : 1592462381 }
{ "_id" : ObjectId("5eeb0c2d4d057134880073b6"), "uid" : "uid1", "grade" : 3, "class" : 5, "subject" : "history", "score" : 91, "createTime" : 1592462381 }
{ "_id" : ObjectId("5eeb0c2d4d057134880073b7"), "uid" : "uid1", "grade" : 3, "class" : 5, "subject" : "biology", "score" : 94, "createTime" : 1592462381 }
{ "_id" : ObjectId("5eeb0c2d4d057134880073b8"), "uid" : "uid2", "grade" : 3, "class" : 9, "subject" : "math", "score" : 30, "createTime" : 1592462381 }
{ "_id" : ObjectId("5eeb0c2d4d057134880073b9"), "uid" : "uid2", "grade" : 3, "class" : 9, "subject" : "chinese", "score" : 26, "createTime" : 1592462381 }
{ "_id" : ObjectId("5eeb0c2d4d057134880073ba"), "uid" : "uid2", "grade" : 3, "class" : 9, "subject" : "english", "score" : 28, "createTime" : 1592462381 }
{ "_id" : ObjectId("5eeb0c2d4d057134880073bb"), "uid" : "uid2", "grade" : 3, "class" : 9, "subject" : "science", "score" : 43, "createTime" : 1592462381 }
{ "_id" : ObjectId("5eeb0c2d4d057134880073bc"), "uid" : "uid2", "grade" : 3, "class" : 9, "subject" : "history", "score" : 48, "createTime" : 1592462381 }
{ "_id" : ObjectId("5eeb0c2d4d057134880073bd"), "uid" : "uid2", "grade" : 3, "class" : 9, "subject" : "biology", "score" : 86, "createTime" : 1592462381 }
{ "_id" : ObjectId("5eeb0c2d4d057134880073be"), "uid" : "uid3", "grade" : 2, "class" : 7, "subject" : "math", "score" : 68, "createTime" : 1592462381 }
{ "_id" : ObjectId("5eeb0c2d4d057134880073bf"), "uid" : "uid3", "grade" : 2, "class" : 7, "subject" : "chinese", "score" : 7, "createTime" : 1592462381 }
{ "_id" : ObjectId("5eeb0c2d4d057134880073c0"), "uid" : "uid3", "grade" : 2, "class" : 7, "subject" : "english", "score" : 51, "createTime" : 1592462381 }
{ "_id" : ObjectId("5eeb0c2d4d057134880073c1"), "uid" : "uid3", "grade" : 2, "class" : 7, "subject" : "science", "score" : 88, "createTime" : 1592462381 }
{ "_id" : ObjectId("5eeb0c2d4d057134880073c2"), "uid" : "uid3", "grade" : 2, "class" : 7, "subject" : "history", "score" : 15, "createTime" : 1592462381 }
{ "_id" : ObjectId("5eeb0c2d4d057134880073c3"), "uid" : "uid3", "grade" : 2, "class" : 7, "subject" : "biology", "score" : 54, "createTime" : 1592462381 }

1、$match:篩選文檔流,以僅允許匹配的文檔未經修改地傳遞到下一個管道階段。

//聚合輸出匹配條件uid="uid1"的文檔
db.score.aggregate([{$match:{"uid":"uid1"}}])
{ "_id" : ObjectId("5eeb0c2d4d057134880073b2"), "uid" : "uid1", "grade" : 3, "class" : 5, "subject" : "math", "score" : 50, "createTime" : 1592462381 }
{ "_id" : ObjectId("5eeb0c2d4d057134880073b3"), "uid" : "uid1", "grade" : 3, "class" : 5, "subject" : "chinese", "score" : 94, "createTime" : 1592462381 }
{ "_id" : ObjectId("5eeb0c2d4d057134880073b4"), "uid" : "uid1", "grade" : 3, "class" : 5, "subject" : "english", "score" : 7, "createTime" : 1592462381 }
{ "_id" : ObjectId("5eeb0c2d4d057134880073b5"), "uid" : "uid1", "grade" : 3, "class" : 5, "subject" : "science", "score" : 6, "createTime" : 1592462381 }
{ "_id" : ObjectId("5eeb0c2d4d057134880073b6"), "uid" : "uid1", "grade" : 3, "class" : 5, "subject" : "history", "score" : 91, "createTime" : 1592462381 }
{ "_id" : ObjectId("5eeb0c2d4d057134880073b7"), "uid" : "uid1", "grade" : 3, "class" : 5, "subject" : "biology", "score" : 94, "createTime" : 1592462381 }

2、$group:按指定的標識符表達式對輸入文檔進行分組,併爲每個不同組輸出一個文檔。

//聚合輸出uid1的score總分值
db.score.aggregate([{$match:{"uid":"uid1"}},{$group:{_id:"$uid",total:{$sum:"$score"}}}])
{ "_id" : "uid1", "total" : 342 }

//聚合輸出所有用戶的score總分值
db.score.aggregate([{$group:{_id:"$uid",total:{$sum:"$score"}}}])
{ "_id" : "uid1992", "total" : 188 }
{ "_id" : "uid1988", "total" : 354 }
{ "_id" : "uid1986", "total" : 329 }
{ "_id" : "uid1984", "total" : 403 }
{ "_id" : "uid1980", "total" : 199 }
{ "_id" : "uid1979", "total" : 321 }

3、$sort:通過指定的排序鍵對文檔流重新排序。

//聚合輸出所有人的總分值,並按總分降序排列
db.score.aggregate([{$group:{_id:"$uid",total:{$sum:"$score"}}},{$sort:{total:-1}}])
{ "_id" : "uid1881", "total" : 522 }
{ "_id" : "uid1187", "total" : 507 }
{ "_id" : "uid967", "total" : 497 }
{ "_id" : "uid1112", "total" : 491 }
{ "_id" : "uid758", "total" : 491 }
{ "_id" : "uid623", "total" : 488 }
{ "_id" : "uid249", "total" : 486 }
{ "_id" : "uid1646", "total" : 484 }

4、$count:返回聚合管道此階段的文檔數計數。

//先按uid分組計算總分,然後統計uid個數
db.score.aggregate([{$group:{_id:"$uid",total:{$sum:"$score"}}},{$count:"count"}])
{ "count" : 2000 }

5、$project:重塑流中的每個文檔,例如添加新字段或刪除現有字段。

//第一階段:匹配grade=3的數據;第二階段:控制只輸出uid、grade、score字段
//$project  1--輸出  0--不輸出
db.score.aggregate([{$match:{grade:3}},{$project:{uid:1,grade:1,score:1}}])
{ "_id" : ObjectId("5eeb0c2d4d057134880073b2"), "uid" : "uid1", "grade" : 3, "score" : 50 }
{ "_id" : ObjectId("5eeb0c2d4d057134880073b3"), "uid" : "uid1", "grade" : 3, "score" : 94 }
{ "_id" : ObjectId("5eeb0c2d4d057134880073b4"), "uid" : "uid1", "grade" : 3, "score" : 7 }
{ "_id" : ObjectId("5eeb0c2d4d057134880073b5"), "uid" : "uid1", "grade" : 3, "score" : 6 }
{ "_id" : ObjectId("5eeb0c2d4d057134880073b6"), "uid" : "uid1", "grade" : 3, "score" : 91 }
{ "_id" : ObjectId("5eeb0c2d4d057134880073b7"), "uid" : "uid1", "grade" : 3, "score" : 94 }
{ "_id" : ObjectId("5eeb0c2d4d057134880073b8"), "uid" : "uid2", "grade" : 3, "score" : 30 }
{ "_id" : ObjectId("5eeb0c2d4d057134880073b9"), "uid" : "uid2", "grade" : 3, "score" : 26 }

6、$limit:將未修改的前n個文檔傳遞到管道,其中n是指定的限制文檔數。

//輸出匹配條件的文檔前三條
db.score.aggregate([{$match:{grade:3}},{$project:{uid:1,grade:1,score:1}},{$limit:3}])
{ "_id" : ObjectId("5eeb0c2d4d057134880073b2"), "uid" : "uid1", "grade" : 3, "score" : 50 }
{ "_id" : ObjectId("5eeb0c2d4d057134880073b3"), "uid" : "uid1", "grade" : 3, "score" : 94 }
{ "_id" : ObjectId("5eeb0c2d4d057134880073b4"), "uid" : "uid1", "grade" : 3, "score" : 7 }

7、$unwind:從輸入文檔中解構一個數組字段,以輸出每個元素的文檔。

先準備一下包含數組數據,如下:

{ "_id" : ObjectId("5eec36894d05712824006a32"), "uid" : "uid1", "grade" : 1, "class" : 8, "subject" : "math", "score" : 68, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : [ "huawei", "oppo", "apple" ] }
{ "_id" : ObjectId("5eec36894d05712824006a33"), "uid" : "uid1", "grade" : 1, "class" : 8, "subject" : "chinese", "score" : 33, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : [ "huawei", "oppo", "apple" ] }
{ "_id" : ObjectId("5eec36894d05712824006a34"), "uid" : "uid1", "grade" : 1, "class" : 8, "subject" : "english", "score" : 81, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : [ "huawei", "oppo", "apple" ] }
{ "_id" : ObjectId("5eec36894d05712824006a35"), "uid" : "uid1", "grade" : 1, "class" : 8, "subject" : "science", "score" : 21, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : [ "huawei", "oppo", "apple" ] }
{ "_id" : ObjectId("5eec36894d05712824006a36"), "uid" : "uid1", "grade" : 1, "class" : 8, "subject" : "history", "score" : 82, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : [ "huawei", "oppo", "apple" ] }
{ "_id" : ObjectId("5eec36894d05712824006a37"), "uid" : "uid1", "grade" : 1, "class" : 8, "subject" : "biology", "score" : 5, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : [ "huawei", "oppo", "apple" ] }
{ "_id" : ObjectId("5eec36894d05712824006a38"), "uid" : "uid2", "grade" : 3, "class" : 4, "subject" : "math", "score" : 83, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : [ "vivo", "apple", "mi" ] }
{ "_id" : ObjectId("5eec36894d05712824006a39"), "uid" : "uid2", "grade" : 3, "class" : 4, "subject" : "chinese", "score" : 13, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : [ "vivo", "apple", "mi" ] }
{ "_id" : ObjectId("5eec36894d05712824006a3a"), "uid" : "uid2", "grade" : 3, "class" : 4, "subject" : "english", "score" : 20, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : [ "vivo", "apple", "mi" ] }
{ "_id" : ObjectId("5eec36894d05712824006a3b"), "uid" : "uid2", "grade" : 3, "class" : 4, "subject" : "science", "score" : 50, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : [ "vivo", "apple", "mi" ] }
{ "_id" : ObjectId("5eec36894d05712824006a3c"), "uid" : "uid2", "grade" : 3, "class" : 4, "subject" : "history", "score" : 89, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : [ "vivo", "apple", "mi" ] }
{ "_id" : ObjectId("5eec36894d05712824006a3d"), "uid" : "uid2", "grade" : 3, "class" : 4, "subject" : "biology", "score" : 64, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : [ "vivo", "apple", "mi" ] }

然後使用$unwind展開數組,如下:可以看到每個數組元素單獨輸出了一條文檔。

db.score.aggregate([{$unwind:"$tags"}])
{ "_id" : ObjectId("5eec36894d05712824006a32"), "uid" : "uid1", "grade" : 1, "class" : 8, "subject" : "math", "score" : 68, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : "huawei" }
{ "_id" : ObjectId("5eec36894d05712824006a32"), "uid" : "uid1", "grade" : 1, "class" : 8, "subject" : "math", "score" : 68, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : "oppo" }
{ "_id" : ObjectId("5eec36894d05712824006a32"), "uid" : "uid1", "grade" : 1, "class" : 8, "subject" : "math", "score" : 68, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : "apple" }
{ "_id" : ObjectId("5eec36894d05712824006a33"), "uid" : "uid1", "grade" : 1, "class" : 8, "subject" : "chinese", "score" : 33, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : "huawei" }
{ "_id" : ObjectId("5eec36894d05712824006a33"), "uid" : "uid1", "grade" : 1, "class" : 8, "subject" : "chinese", "score" : 33, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : "oppo" }
{ "_id" : ObjectId("5eec36894d05712824006a33"), "uid" : "uid1", "grade" : 1, "class" : 8, "subject" : "chinese", "score" : 33, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : "apple" }
{ "_id" : ObjectId("5eec36894d05712824006a34"), "uid" : "uid1", "grade" : 1, "class" : 8, "subject" : "english", "score" : 81, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : "huawei" }
{ "_id" : ObjectId("5eec36894d05712824006a34"), "uid" : "uid1", "grade" : 1, "class" : 8, "subject" : "english", "score" : 81, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : "oppo" }
{ "_id" : ObjectId("5eec36894d05712824006a34"), "uid" : "uid1", "grade" : 1, "class" : 8, "subject" : "english", "score" : 81, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : "apple" }
{ "_id" : ObjectId("5eec36894d05712824006a35"), "uid" : "uid1", "grade" : 1, "class" : 8, "subject" : "science", "score" : 21, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : "huawei" }
{ "_id" : ObjectId("5eec36894d05712824006a35"), "uid" : "uid1", "grade" : 1, "class" : 8, "subject" : "science", "score" : 21, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : "oppo" }
{ "_id" : ObjectId("5eec36894d05712824006a35"), "uid" : "uid1", "grade" : 1, "class" : 8, "subject" : "science", "score" : 21, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : "apple" }
{ "_id" : ObjectId("5eec36894d05712824006a36"), "uid" : "uid1", "grade" : 1, "class" : 8, "subject" : "history", "score" : 82, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : "huawei" }
{ "_id" : ObjectId("5eec36894d05712824006a36"), "uid" : "uid1", "grade" : 1, "class" : 8, "subject" : "history", "score" : 82, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : "oppo" }
{ "_id" : ObjectId("5eec36894d05712824006a36"), "uid" : "uid1", "grade" : 1, "class" : 8, "subject" : "history", "score" : 82, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : "apple" }
{ "_id" : ObjectId("5eec36894d05712824006a37"), "uid" : "uid1", "grade" : 1, "class" : 8, "subject" : "biology", "score" : 5, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : "huawei" }
{ "_id" : ObjectId("5eec36894d05712824006a37"), "uid" : "uid1", "grade" : 1, "class" : 8, "subject" : "biology", "score" : 5, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : "oppo" }
{ "_id" : ObjectId("5eec36894d05712824006a37"), "uid" : "uid1", "grade" : 1, "class" : 8, "subject" : "biology", "score" : 5, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : "apple" }
{ "_id" : ObjectId("5eec36894d05712824006a38"), "uid" : "uid2", "grade" : 3, "class" : 4, "subject" : "math", "score" : 83, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : "vivo" }
{ "_id" : ObjectId("5eec36894d05712824006a38"), "uid" : "uid2", "grade" : 3, "class" : 4, "subject" : "math", "score" : 83, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : "apple" }

8、$redact:通過基於文檔本身中存儲的信息限制每個文檔的內容,來重塑流中的每個文檔。

//輸出符合條件grade>class的文檔
db.score.aggregate([
... {
... $redact: {
... "$cond": [
... { "$gt": ["$grade", "$class"] },
... "$$KEEP",
... "$$PRUNE"
... ]
... }
... }
... ])
{ "_id" : ObjectId("5eec36894d05712824006a80"), "uid" : "uid14", "grade" : 2, "class" : 1, "subject" : "math", "score" : 1, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : [ "mi", "vivo" ] }
{ "_id" : ObjectId("5eec36894d05712824006a81"), "uid" : "uid14", "grade" : 2, "class" : 1, "subject" : "chinese", "score" : 0, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : [ "mi", "vivo" ] }
{ "_id" : ObjectId("5eec36894d05712824006a82"), "uid" : "uid14", "grade" : 2, "class" : 1, "subject" : "english", "score" : 72, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : [ "mi", "vivo" ] }
{ "_id" : ObjectId("5eec36894d05712824006a83"), "uid" : "uid14", "grade" : 2, "class" : 1, "subject" : "science", "score" : 82, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : [ "mi", "vivo" ] }
{ "_id" : ObjectId("5eec36894d05712824006a84"), "uid" : "uid14", "grade" : 2, "class" : 1, "subject" : "history", "score" : 47, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : [ "mi", "vivo" ] }
{ "_id" : ObjectId("5eec36894d05712824006a85"), "uid" : "uid14", "grade" : 2, "class" : 1, "subject" : "biology", "score" : 21, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : [ "mi", "vivo" ] }
{ "_id" : ObjectId("5eec36894d05712824006abc"), "uid" : "uid24", "grade" : 4, "class" : 1, "subject" : "math", "score" : 28, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : [ "mi", "apple", "vivo", "samsung" ] }
{ "_id" : ObjectId("5eec36894d05712824006abd"), "uid" : "uid24", "grade" : 4, "class" : 1, "subject" : "chinese", "score" : 45, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : [ "mi", "apple", "vivo", "samsung" ] }
{ "_id" : ObjectId("5eec36894d05712824006abe"), "uid" : "uid24", "grade" : 4, "class" : 1, "subject" : "english", "score" : 48, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : [ "mi", "apple", "vivo", "samsung" ] }
{ "_id" : ObjectId("5eec36894d05712824006abf"), "uid" : "uid24", "grade" : 4, "class" : 1, "subject" : "science", "score" : 1, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : [ "mi", "apple", "vivo", "samsung" ] }
{ "_id" : ObjectId("5eec36894d05712824006ac0"), "uid" : "uid24", "grade" : 4, "class" : 1, "subject" : "history", "score" : 8, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : [ "mi", "apple", "vivo", "samsung" ] }
{ "_id" : ObjectId("5eec36894d05712824006ac1"), "uid" : "uid24", "grade" : 4, "class" : 1, "subject" : "biology", "score" : 26, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : [ "mi", "apple", "vivo", "samsung" ] }
{ "_id" : ObjectId("5eec36894d05712824006ada"), "uid" : "uid29", "grade" : 4, "class" : 3, "subject" : "math", "score" : 33, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : [ "huawei", "samsung", "mi" ] }
{ "_id" : ObjectId("5eec36894d05712824006adb"), "uid" : "uid29", "grade" : 4, "class" : 3, "subject" : "chinese", "score" : 21, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : [ "huawei", "samsung", "mi" ] }

9、$addFields:將新字段添加到文檔。

//爲所有文檔添加字段type="student"
db.score.aggregate([{$addFields:{'type':'student'}}])
{ "_id" : ObjectId("5eeb0c2d4d057134880073b2"), "uid" : "uid1", "grade" : 3, "class" : 5, "subject" : "math", "score" : 50, "createTime" : 1592462381, "type" : "student" }

//爲所有文檔添加字段total,值爲score求和
db.score.aggregate([{$addFields:{'total':{$sum:"$score"}}}])
{ "_id" : ObjectId("5eeb0c2d4d057134880073b2"), "uid" : "uid1", "grade" : 3, "class" : 5, "subject" : "math", "score" : 50, "createTime" : 1592462381, "total" : 50 }

10、$lookup:對同一數據庫中的另一個集合執行左外部 聯接,以過濾“聯接”集合中的文檔以進行處理。

再添加一個集合student,數據量2000,包含uid、name、sex、birhday字段

db.student.find()
{ "_id" : "uid1", "name" : "stu1", "sex" : 0, "birthday" : 1592546162, "createTime" : 1592546162, "updateTime" : 1592546162 }
{ "_id" : "uid2", "name" : "stu2", "sex" : 0, "birthday" : 1592546162, "createTime" : 1592546162, "updateTime" : 1592546162 }
{ "_id" : "uid3", "name" : "stu3", "sex" : 0, "birthday" : 1592546162, "createTime" : 1592546162, "updateTime" : 1592546162 }
{ "_id" : "uid4", "name" : "stu4", "sex" : 0, "birthday" : 1592546162, "createTime" : 1592546162, "updateTime" : 1592546162 }
{ "_id" : "uid5", "name" : "stu5", "sex" : 0, "birthday" : 1592546162, "createTime" : 1592546162, "updateTime" : 1592546162 }
{ "_id" : "uid6", "name" : "stu6", "sex" : 1, "birthday" : 1592546162, "createTime" : 1592546162, "updateTime" : 1592546162 }
{ "_id" : "uid7", "name" : "stu7", "sex" : 0, "birthday" : 1592546162, "createTime" : 1592546162, "updateTime" : 1592546162 }
{ "_id" : "uid8", "name" : "stu8", "sex" : 1, "birthday" : 1592546162, "createTime" : 1592546162, "updateTime" : 1592546162 }
{ "_id" : "uid9", "name" : "stu9", "sex" : 0, "birthday" : 1592546162, "createTime" : 1592546162, "updateTime" : 1592546162 }

接下來測試$lookup,可以看到score中此學生的分數信息在scoreInfos中

db.student.aggregate([
... {$match: { sex: 0}},
... {
... $lookup:
...    {
...        from: "score",
...        localField: "_id",
...        foreignField: "uid",
...        as: "scoreInfos"
...    }
... }
... ])
{
    "_id" : "uid1",
    "name" : "stu1",
    "sex" : 0,
    "birthday" : 1592546162,
    "createTime" : 1592546162,
    "updateTime" : 1592546162,
    "scoreInfos" : [
{"_id":ObjectId("5eec36894d05712824006a32"),"uid":"uid1","grade":1,"class":8,"subject":"math","score":68,"createTime":1592538761,"updateTime":1592538761,"tags":["huawei","oppo","apple"]},
{"_id":ObjectId("5eec36894d05712824006a33"),"uid":"uid1","grade":1,"class":8,"subject":"chinese","score":33,"createTime":1592538761,"updateTime":1592538761,"tags":["huawei","oppo","apple"]},
{"_id":ObjectId("5eec36894d05712824006a34"),"uid":"uid1","grade":1,"class":8,"subject":"english","score":81,"createTime":1592538761,"updateTime":1592538761,"tags":["huawei","oppo","apple"]},
{"_id":ObjectId("5eec36894d05712824006a35"),"uid":"uid1","grade":1,"class":8,"subject":"science","score":21,"createTime":1592538761,"updateTime":1592538761,"tags":["huawei","oppo","apple"]},
{"_id":ObjectId("5eec36894d05712824006a36"),"uid":"uid1","grade":1,"class":8,"subject":"history","score":82,"createTime":1592538761,"updateTime":1592538761,"tags":["huawei","oppo","apple"]},
{"_id":ObjectId("5eec36894d05712824006a37"),"uid":"uid1","grade":1,"class":8,"subject":"biology","score":5,"createTime":1592538761,"updateTime":1592538761,"tags":["huawei","oppo","apple"]}]
     ] 
}

11、$geoNear:根據與地理空間點的接近程度返回有序的文檔流。

12、$set:將新字段添加到文檔。$set是$addFields的別名。

13、$unset:從文檔中刪除/排除字段。$unset是$project刪除字段的階段的別名。

14、$sortByCount:根據指定表達式的值對傳入文檔進行分組,然後計算每個不同組中的文檔數。

15、$skip:跳過前n個文檔,其中n是指定的跳過編號,並將其餘未修改的文檔傳遞到管道。

16、$replaceRoot:用指定的嵌入式文檔替換文檔。

17、$replaceWith:用指定的嵌入式文檔替換文檔。$replaceWith是$replaceRoot的別名。

18、$sample:從其輸入中隨機選擇指定數量的文檔。

19、$out:將聚合管道的結果文檔寫入集合。要使用該$out階段,它必須是管道中的最後一個階段。

20、$planCacheStats:返回集合的計劃緩存信息。

21、$merge:將聚合管道的結果文檔寫入集合。要使用該$merge階段,它必須是管道中的最後一個階段。(4.2版中的新功能)

22、$listSessions:列出所有活動時間已經足夠長以傳播到system.sessions集合的會話。

23、$indexStats:返回有關集合每個索引使用情況的統計信息。

24、$graphLookup:對集合執行遞歸搜索。

25、$facet:在同一階段的同一組輸入文檔上處理多個聚合管道。支持在一個階段中創建能夠表徵多維或多面數據的多面聚合。

26、$collStats:返回有關集合或視圖的統計信息。

27、$bucket:根據指定的表達式和存儲區邊界將傳入文檔分類爲多個組,稱爲存儲區。

28、$bucketAuto:根據指定的表達式將傳入文檔分類爲特定數量的組,稱爲存儲桶。自動確定存儲區邊界,以嘗試將文檔平均分配到指定數量的存儲區中。

三、高級聚合查詢

1、$match與$group:

//第一階段:$match條件過濾grade=1的文檔;第二階段:$group通過uid分組,並計算score的總分值
db.score.aggregate([{$match:{grade:1}},{$group:{_id:"$uid",total:{$sum:"$score"}}}])
{ "_id" : "uid1992", "total" : 188 }
{ "_id" : "uid1982", "total" : 154 }
{ "_id" : "uid1979", "total" : 321 }
{ "_id" : "uid1976", "total" : 402 }
{ "_id" : "uid1975", "total" : 310 }
{ "_id" : "uid1967", "total" : 213 }
{ "_id" : "uid1955", "total" : 258 }
{ "_id" : "uid1932", "total" : 259 }
{ "_id" : "uid1926", "total" : 397 }
{ "_id" : "uid1923", "total" : 166 }
{ "_id" : "uid1916", "total" : 273 }

//第三階段:$match條件過濾總分total>300的文檔
db.score.aggregate([{$match:{grade:1}},{$group:{_id:"$uid",total:{$sum:"$score"}}},{$match:{total:{$gt:300}}}])
{ "_id" : "uid1979", "total" : 321 }
{ "_id" : "uid1976", "total" : 402 }
{ "_id" : "uid1975", "total" : 310 }
{ "_id" : "uid1926", "total" : 397 }
{ "_id" : "uid1927", "total" : 343 }
{ "_id" : "uid1869", "total" : 332 }
{ "_id" : "uid1867", "total" : 328 }
{ "_id" : "uid1865", "total" : 415 }

//查詢grade=4的所有班級的所有科目分別的總分
db.score.aggregate([{$match:{grade:4}},{$group:{_id:{"class":"$class","subject":"$subject"},count:{$sum:"$score"}}}])
{ "_id" : { "class" : 2, "subject" : "biology" }, "count" : 1526 }
{ "_id" : { "class" : 2, "subject" : "science" }, "count" : 1921 }
{ "_id" : { "class" : 2, "subject" : "math" }, "count" : 1954 }
{ "_id" : { "class" : 2, "subject" : "history" }, "count" : 1852 }
{ "_id" : { "class" : 9, "subject" : "science" }, "count" : 2727 }
{ "_id" : { "class" : 7, "subject" : "history" }, "count" : 2129 }
{ "_id" : { "class" : 7, "subject" : "biology" }, "count" : 2009 }
{ "_id" : { "class" : 7, "subject" : "english" }, "count" : 2089 }
{ "_id" : { "class" : 7, "subject" : "math" }, "count" : 2298 }
{ "_id" : { "class" : 9, "subject" : "math" }, "count" : 2746 }
{ "_id" : { "class" : 5, "subject" : "biology" }, "count" : 2171 }
{ "_id" : { "class" : 5, "subject" : "history" }, "count" : 2544 }
{ "_id" : { "class" : 5, "subject" : "science" }, "count" : 2543 }
{ "_id" : { "class" : 5, "subject" : "english" }, "count" : 2544 }
{ "_id" : { "class" : 2, "subject" : "english" }, "count" : 2046 }
{ "_id" : { "class" : 3, "subject" : "biology" }, "count" : 3277 }
{ "_id" : { "class" : 3, "subject" : "history" }, "count" : 2711 }
{ "_id" : { "class" : 3, "subject" : "chinese" }, "count" : 3559 }
{ "_id" : { "class" : 9, "subject" : "history" }, "count" : 3164 }
{ "_id" : { "class" : 7, "subject" : "chinese" }, "count" : 2199 }

2、$match、$unwind與$group:

//聚合輸出每個標籤的攜帶者數量
db.score.aggregate([{$match:{grade:3}},{$unwind:"$tags"},{$group:{_id:"$tags",count:{$sum:1}}}])
{ "_id" : "huawei", "count" : 1572 }
{ "_id" : "samsung", "count" : 1392 }
{ "_id" : "oppo", "count" : 1614 }
{ "_id" : "mi", "count" : 1596 }
{ "_id" : "vivo", "count" : 1608 }
{ "_id" : "apple", "count" : 1560 }

//聚合輸出每個標籤的攜帶者數量,並降序排列
db.score.aggregate([{$match:{grade:3}},{$unwind:"$tags"},{$group:{_id:"$tags",count:{$sum:1}}},{$sort:{count:-1}}])
{ "_id" : "oppo", "count" : 1614 }
{ "_id" : "vivo", "count" : 1608 }
{ "_id" : "mi", "count" : 1596 }
{ "_id" : "huawei", "count" : 1572 }
{ "_id" : "apple", "count" : 1560 }
{ "_id" : "samsung", "count" : 1392 }

//聚合輸出符合條件的學生分別屬於在哪個標籤組
db.score.aggregate([{$match:{grade:3,class:1,subject:'math'}},{$unwind:"$tags"},{$group:{_id:"$tags",uids:{$addToSet:"$uid"}}}])
{ "_id" : "huawei", "uids" : [ "uid1926", "uid1466", "uid1407", "uid1324", "uid1688", "uid1703", "uid1266", "uid1154", "uid973", "uid834", "uid821", "uid787", "uid1489", "uid1399", "uid547", "uid734", "uid382", "uid1657", "uid855", "uid558", "uid1641", "uid278", "uid903", "uid250", "uid1358", "uid1444", "uid273", "uid1264", "uid185", "uid372", "uid710", "uid1328", "uid1184", "uid87" ] }
{ "_id" : "samsung", "uids" : [ "uid1641", "uid1596", "uid1444", "uid1220", "uid1339", "uid1184", "uid1703", "uid1688", "uid1060", "uid787", "uid1057", "uid570", "uid1163", "uid250", "uid1358", "uid734", "uid1740", "uid1407", "uid39", "uid534" ] }
{ "_id" : "oppo", "uids" : [ "uid1940", "uid1893", "uid1657", "uid1466", "uid1489", "uid1399", "uid1740", "uid1392", "uid1266", "uid1220", "uid654", "uid1105", "uid547", "uid734", "uid1926", "uid257", "uid834", "uid1163", "uid973", "uid1444", "uid273", "uid250", "uid278", "uid102", "uid855", "uid1184", "uid87", "uid1328", "uid283", "uid1206", "uid39" ] }
{ "_id" : "apple", "uids" : [ "uid1940", "uid1596", "uid1466", "uid1407", "uid1392", "uid1358", "uid1154", "uid1324", "uid1060", "uid1489", "uid1022", "uid880", "uid821", "uid654", "uid1206", "uid534", "uid641", "uid283", "uid710", "uid1264", "uid273", "uid1339", "uid185", "uid372", "uid31", "uid257", "uid570", "uid834", "uid1641", "uid278", "uid102", "uid855" ] }
{ "_id" : "vivo", "uids" : [ "uid1407", "uid1392", "uid1703", "uid1688", "uid1324", "uid1339", "uid1220", "uid1154", "uid1057", "uid903", "uid1163", "uid834", "uid787", "uid1206", "uid641", "uid547", "uid734", "uid1105", "uid654", "uid459", "uid1328", "uid283", "uid710", "uid87", "uid880", "uid558", "uid102", "uid855", "uid31" ] }
{ "_id" : "mi", "uids" : [ "uid1893", "uid1740", "uid1466", "uid1358", "uid1328", "uid1184", "uid1266", "uid1060", "uid1596", "uid973", "uid903", "uid821", "uid1022", "uid787", "uid547", "uid1657", "uid382", "uid880", "uid1641", "uid278", "uid185", "uid459", "uid372", "uid39", "uid641", "uid31", "uid1926", "uid1163", "uid257", "uid570" ] }

3、$match、$lookup與$unwind、$group:

db.student.aggregate([
... {$match: { sex: 0}},
... {
... $lookup:
...    {
...        from: "score",
...        localField: "_id",
...        foreignField: "uid",
...        as: "scoreInfos"
...    }
... },
... { "$unwind": "$scoreInfos" },
... ])
{ "_id" : "uid1", "name" : "stu1", "sex" : 0, "birthday" : 1592546162, "createTime" : 1592546162, "updateTime" : 1592546162, "scoreInfos" : { "_id" : ObjectId("5eec36894d05712824006a32"), "uid" : "uid1", "grade" : 1, "class" : 8, "subject" : "math", "score" : 68, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : [ "huawei", "oppo", "apple" ] } }
{ "_id" : "uid1", "name" : "stu1", "sex" : 0, "birthday" : 1592546162, "createTime" : 1592546162, "updateTime" : 1592546162, "scoreInfos" : { "_id" : ObjectId("5eec36894d05712824006a33"), "uid" : "uid1", "grade" : 1, "class" : 8, "subject" : "chinese", "score" : 33, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : [ "huawei", "oppo", "apple" ] } }
{ "_id" : "uid1", "name" : "stu1", "sex" : 0, "birthday" : 1592546162, "createTime" : 1592546162, "updateTime" : 1592546162, "scoreInfos" : { "_id" : ObjectId("5eec36894d05712824006a34"), "uid" : "uid1", "grade" : 1, "class" : 8, "subject" : "english", "score" : 81, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : [ "huawei", "oppo", "apple" ] } }
{ "_id" : "uid1", "name" : "stu1", "sex" : 0, "birthday" : 1592546162, "createTime" : 1592546162, "updateTime" : 1592546162, "scoreInfos" : { "_id" : ObjectId("5eec36894d05712824006a35"), "uid" : "uid1", "grade" : 1, "class" : 8, "subject" : "science", "score" : 21, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : [ "huawei", "oppo", "apple" ] } }
{ "_id" : "uid1", "name" : "stu1", "sex" : 0, "birthday" : 1592546162, "createTime" : 1592546162, "updateTime" : 1592546162, "scoreInfos" : { "_id" : ObjectId("5eec36894d05712824006a36"), "uid" : "uid1", "grade" : 1, "class" : 8, "subject" : "history", "score" : 82, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : [ "huawei", "oppo", "apple" ] } }
{ "_id" : "uid1", "name" : "stu1", "sex" : 0, "birthday" : 1592546162, "createTime" : 1592546162, "updateTime" : 1592546162, "scoreInfos" : { "_id" : ObjectId("5eec36894d05712824006a37"), "uid" : "uid1", "grade" : 1, "class" : 8, "subject" : "biology", "score" : 5, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : [ "huawei", "oppo", "apple" ] } }
{ "_id" : "uid2", "name" : "stu2", "sex" : 0, "birthday" : 1592546162, "createTime" : 1592546162, "updateTime" : 1592546162, "scoreInfos" : { "_id" : ObjectId("5eec36894d05712824006a38"), "uid" : "uid2", "grade" : 3, "class" : 4, "subject" : "math", "score" : 83, "createTime" : 1592538761, "updateTime" : 1592538761, "tags" : [ "vivo", "apple", "mi" ] } }

//統計包含mi標籤的學生人數
 db.student.aggregate([
... {$match: { sex: 0}},
... {
... $lookup:
...    {
...        from: "score",
...        localField: "_id",
...        foreignField: "uid",
...        as: "scoreInfos"
...    }
... },
... { "$unwind": "$scoreInfos" },
... { "$match": { "scoreInfos.tags": "mi" } },
... { "$group": { _id:"$scoreInfos.uid" } },
... { "$count": "count" }
... ])
{ "count" : 498 }

4、$group中的$first、$last

//分別查詢男生女生中第一個和最後一個進入系統的人
db.student.aggregate([
...     {"$sort": {"createTime": -1}},
...     {"$group": {_id: "$sex",
...         first: { $first: "$$ROOT" },
...         last: { $last: "$$ROOT" }}
...     },
... ])
{ "_id" : 1, "first" : { "_id" : "uid2077", "name" : "stu2077", "sex" : 1, "birthday" : 1592555330, "createTime" : 1592555330, "updateTime" : 1592555330 }, "last" : { "_id" : "uid1997", "name" : "stu1997", "sex" : 1, "birthday" : 1592546162, "createTime" : 1592546162, "updateTime" : 1592546162 } }
{ "_id" : 0, "first" : { "_id" : "uid2079", "name" : "stu2079", "sex" : 0, "birthday" : 1592555340, "createTime" : 1592555340, "updateTime" : 1592555340 }, "last" : { "_id" : "uid2000", "name" : "stu2000", "sex" : 0, "birthday" : 1592546162, "createTime" : 1592546162, "updateTime" : 1592546162 } }

5、$project中的$subtract,計算差值,得到first.birthday減去last.birthday的值

 db.student.aggregate([
...     {"$sort": {"createTime": -1}},
...     {"$group": {_id: "$sex",
...         first: { $first: "$$ROOT" },
...         last: { $last: "$$ROOT" }}
...     },
... {"$project":{"total":{$subtract:["$first.birthday","$last.birthday"]}}},
... {"$match":{"total":{$gt:100}}}
... ])
{ "_id" : 1, "total" : 9168 }
{ "_id" : 0, "total" : 9178 }

OK,以上學習MongoDB的高級聚合查詢,這裏沒有考慮效率問題,畢竟測試數據也較少。以後接着更深入的學習吧!^_^

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章