1. MongoDB 聚合管道簡介
使用聚合管道可以對集合中的文檔進行變換和組合,常用於多表關聯查詢、數據的統計。
db.COLLECTION_NAME.aggregate() 方法用來構建和使用聚合管道,下圖是官網給的實例,可以看出來聚合管道的用法還是比較簡單的。
2. MongoDB Aggregation 管道操作符與表達式
常用的管道操作符有以下這些:
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
修改文檔的結構,可以用來重命名、增加或刪除文檔中的字段。
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
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
}
]
}