MongoDB 高级查询 aggregate 聚合管道
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
}
]
}
下一篇: 一些免费的 UI 和图标资源