1. MongoDB 聚合管道簡介
使用聚合管道可以對集合中的文檔進行變換群組合,常用于多表關聯查詢、資料的統計。
db.COLLECTION_NAME.aggregate() 方法用來建構和使用聚合管道,下圖是官網給的執行個體,可以看出來聚合管道的用法還是比較簡單的。

2. MongoDB Aggregation 管道操作符與表達式
常用的管道操作符有以下這些:
MySQL 和 MongoDB 的聚合 對比 :
管道操作符作為 “ 鍵 ”, 所對應的“ 值 ”叫做管道表達式, 如 {$match:{status:"A"}} , $match 稱為管道操作符,而 status:"A"稱為管道表達式,每個管道表達式是一個文檔結構,它是由字段名、字段值、和一些表達式操作符組成的,常用的表達式操作符有以下這些。
3. 模拟資料
為了說明每個管道操作符的作用,将以下面資料為參考,分别有order和order_item兩個集合。
order集合裡的資料
{
"_id": ObjectId("5e6f15c1eb57cc45bde8130b"),
"order_id": "1",
"uid": 10,
"trade_no": "111",
"all_price": 100,
"all_num": 2
}
{
"_id": ObjectId("5e6f15cbeb57cc45bde8130c"),
"order_id": "2",
"uid": 7,
"trade_no": "222",
"all_price": 90,
"all_num": 2
}
{
"_id": ObjectId("5e6f15d4eb57cc45bde8130d"),
"order_id": "3",
"uid": 9,
"trade_no": "333",
"all_price": 20,
"all_num": 6
}
複制
order_item集合裡的資料
{
"_id": ObjectId("5e6f15dbeb57cc45bde8130e"),
"order_id": "1",
"title": "商品滑鼠 1",
"price": 50,
"num": 1
}
{
"_id": ObjectId("5e6f15e2eb57cc45bde8130f"),
"order_id": "1",
"title": "商品鍵盤 2",
"price": 50,
"num": 1
}
{
"_id": ObjectId("5e6f15e8eb57cc45bde81310"),
"order_id": "1",
"title": "商品鍵盤 3",
"price": 0,
"num": 1
}
{
"_id": ObjectId("5e6f15f1eb57cc45bde81311"),
"order_id": "2",
"title": "牛奶",
"price": 50,
"num": 1
}
{
"_id": ObjectId("5e6f15faeb57cc45bde81312"),
"order_id": "2",
"title": "酸奶",
"price": 40,
"num": 1
}
{
"_id": ObjectId("5e6f1603eb57cc45bde81313"),
"order_id": "3",
"title": "礦泉水",
"price": 2,
"num": 5
}
{
"_id": ObjectId("5e6f160aeb57cc45bde81314"),
"order_id": "3",
"title": "毛巾",
"price": 10,
"num": 1
}
複制
4. 管道操作符 $project
修改文檔的結構,可以用來重命名、增加或删除文檔中的字段。
例:要求查找 order 集合, 隻傳回文檔中 trade_no 和 all_price 字段。
db.order.aggregate([
{
$project:{ trade_no:1, all_price:1 }
}
])
複制
執行結果:
{ "_id" : ObjectId("5e6f15c1eb57cc45bde8130b"), "trade_no" : "111", "all_price" : 100 }
{ "_id" : ObjectId("5e6f15cbeb57cc45bde8130c"), "trade_no" : "222", "all_price" : 90 }
{ "_id" : ObjectId("5e6f15d4eb57cc45bde8130d"), "trade_no" : "333", "all_price" : 20 }
複制
5. 管道操作符 $match
用于過濾文檔,用法類似于 find() 方法中的參數。
例:要求查找 order 集合,隻傳回文檔中 trade_no 和 all_price 字段,并隻顯示 all_price 大于等于90的記錄。
db.order.aggregate([
{
$project: { trade_no: 1, all_price: 1}
},
{
$match: {
"all_price": {$gte: 90}
}
}
])
複制
執行結果:
{ "_id" : ObjectId("5e6f15c1eb57cc45bde8130b"), "trade_no" : "111", "all_price" : 100 }
{ "_id" : ObjectId("5e6f15cbeb57cc45bde8130c"), "trade_no" : "222", "all_price" : 90 }
複制
6. 管道操作符 $group
将集合中的文檔進行分組,可用于統計結果。
例:統計每個訂單的訂單數量,按照訂單号分組。
db.order_item.aggregate([
{
$group:
{_id: "$order_id", total: {$sum: "$num"}
}
}
])
複制
執行結果:
{ "_id" : "2", "total" : 2 }
{ "_id" : "3", "total" : 6 }
{ "_id" : "1", "total" : 3 }
複制
7. 管道操作符 $sort
将集合中的文檔進行排序。
例:要求查找 order 集合, 隻傳回文檔中 trade_no 和 all_price 字段,隻顯示 all_price 大于等于90的記錄,并以all_price進行降序排列。
db.order.aggregate([
{
$project: { trade_no: 1, all_price: 1}
},
{
$match: {
"all_price": {$gte: 90}
}
},
{
$sort: {"all_price": -1}
}
])
複制
執行結果:
{ "_id" : ObjectId("5e6f15c1eb57cc45bde8130b"), "trade_no" : "111", "all_price" : 100 }
{ "_id" : ObjectId("5e6f15cbeb57cc45bde8130c"), "trade_no" : "222", "all_price" : 90 }
複制
8. 管道操作符 $limit
限制查詢結果的數量。
例:要求查找 order 集合,隻傳回文檔中 trade_no 和 all_price 字段,隻顯示 all_price 大于等于90的記錄,以all_price進行降序排列,并隻顯示1條記錄。
db.order.aggregate([
{
$project: { trade_no: 1, all_price: 1}
},
{
$match: {
"all_price": {$gte: 90}
}
},
{
$sort: {"all_price": -1}
},
{
$limit: 1
}
])
複制
執行結果:
{ "_id" : ObjectId("5e6f15c1eb57cc45bde8130b"), "trade_no" : "111", "all_price" : 100 }
複制
9. 管道操作符 $skip
對查詢結果跳過幾條記錄進行顯示。
例:要求查找 order 集合,隻傳回文檔中 trade_no 和 all_price 字段,隻顯示 all_price 大于等于90的記錄,以 all_price 進行降序排列,并跳過1條記錄顯示其結果。
db.order.aggregate([
{
$project: { trade_no: 1, all_price: 1}
},
{
$match: {
"all_price": {$gte: 90}
}
},
{
$sort: {"all_price": -1}
},
{
$skip: 1
}
])
複制
執行結果:
{ "_id" : ObjectId("5e6f15cbeb57cc45bde8130c"), "trade_no" : "222", "all_price" : 90 }
複制
10. 管道操作符 $lookup
對要查詢的結果時行多表關聯查詢。
例:查詢 order 集合,關聯到order_item集合,将 order 中 order_id 與 order_item 中order_id 相同的記錄顯示出來,并将結果取名為 items。
db.order.aggregate([
{
$lookup: {
from: "order_item",
localField: "order_id",
foreignField: "order_id",
as: "items"
}
}
])
複制
執行結果:
{
"_id": ObjectId("5e6f15c1eb57cc45bde8130b"),
"order_id": "1",
"uid": 10,
"trade_no": "111",
"all_price": 100,
"all_num": 2,
"items": [
{
"_id": ObjectId("5e6f15dbeb57cc45bde8130e"),
"order_id": "1",
"title": "商品滑鼠 1",
"price": 50,
"num": 1
},
{
"_id": ObjectId("5e6f15e2eb57cc45bde8130f"),
"order_id": "1",
"title": "商品鍵盤 2",
"price": 50,
"num": 1
},
{
"_id": ObjectId("5e6f15e8eb57cc45bde81310"),
"order_id": "1",
"title": "商品鍵盤 3",
"price": 0,
"num": 1
}
]
}
{
"_id": ObjectId("5e6f15cbeb57cc45bde8130c"),
"order_id": "2",
"uid": 7,
"trade_no": "222",
"all_price": 90,
"all_num": 2,
"items": [
{
"_id": ObjectId("5e6f15f1eb57cc45bde81311"),
"order_id": "2",
"title": "牛奶",
"price": 50,
"num": 1
},
{
"_id": ObjectId("5e6f15faeb57cc45bde81312"),
"order_id": "2",
"title": "酸奶",
"price": 40,
"num": 1
}
]
}
{
"_id": ObjectId("5e6f15d4eb57cc45bde8130d"),
"order_id": "3",
"uid": 9,
"trade_no": "333",
"all_price": 20,
"all_num": 6,
"items": [
{
"_id": ObjectId("5e6f1603eb57cc45bde81313"),
"order_id": "3",
"title": "礦泉水",
"price": 2,
"num": 5
},
{
"_id": ObjectId("5e6f160aeb57cc45bde81314"),
"order_id": "3",
"title": "毛巾",
"price": 10,
"num": 1
}
]
}
複制