高级查询 聚合管道(aggregate pipeline)
使用聚合管道可以对集合中的文档进行变换和组合
用于表关联查询、数据的统计等。
MongoDB 使用 db.COLLECTION_NAME.aggregate([{<stage>} , ... ]) 方法来构建和使用聚合管道。
MongoDB Aaggregation 管道操作符与表达式:
① $project:增加、删除、重命名字段
② $match:条件匹配,只有满足条件的文档才能进入下一阶段
③ $limit:限制结果的数量
④ $skip:跳过文档的数量
⑤ $sort:条件排序
⑥ $lookup:用以引入其他集合的数据(表关联查询)
管道表达式:
管道操作符作为“键”,所对应的“值”叫做管道表达式
例如 :{$match:{status:"A"}},$match 称为管道操作符,而status:"A"称为管道表达式,是管道操作符的操作数。
每个管道表达式是一个文档结构,它是由字段名,字段值,和一些表达式操作符组成的。
先建立两个数据库:订单 order 和 商品 orderItem
> use order switched to db order > db.order.find() { "_id" : ObjectId("5eec580554173c45e32c1d75"), "order_id" : 1, "trade_sum" : 10, "all_price" : 101, "all_num" : 11 } { "_id" : ObjectId("5eec580554173c45e32c1d76"), "order_id" : 2, "trade_sum" : 20, "all_price" : 102, "all_num" : 12 } { "_id" : ObjectId("5eec580554173c45e32c1d77"), "order_id" : 3, "trade_sum" : 30, "all_price" : 103, "all_num" : 13 } { "_id" : ObjectId("5eec580554173c45e32c1d78"), "order_id" : 4, "trade_sum" : 40, "all_price" : 104, "all_num" : 14 } { "_id" : ObjectId("5eec580554173c45e32c1d79"), "order_id" : 5, "trade_sum" : 50, "all_price" : 105, "all_num" : 15 } >
> use orderItem switched to db orderItem > db.orderItem.find() { "_id" : ObjectId("5eec590f54173c45e32c1d7a"), "order_id" : 1, "title" : "order_id=1,item1", "price" : 11, "num" : 4 } { "_id" : ObjectId("5eec590f54173c45e32c1d7b"), "order_id" : 1, "title" : "order_id=1,item2", "price" : 12, "num" : 5 } { "_id" : ObjectId("5eec590f54173c45e32c1d7c"), "order_id" : 1, "title" : "order_id=1,item3", "price" : 13, "num" : 6 } { "_id" : ObjectId("5eec596154173c45e32c1d7d"), "order_id" : 2, "title" : "order_id=2,item1", "price" : 16, "num" : 6 } { "_id" : ObjectId("5eec596154173c45e32c1d7e"), "order_id" : 2, "title" : "order_id=2,item2", "price" : 17, "num" : 7 } { "_id" : ObjectId("5eec596154173c45e32c1d7f"), "order_id" : 2, "title" : "order_id=2,item3", "price" : 18, "num" : 8 } { "_id" : ObjectId("5eec596154173c45e32c1d80"), "order_id" : 2, "title" : "order_id=2,item4", "price" : 19, "num" : 9 } { "_id" : ObjectId("5eec599454173c45e32c1d81"), "order_id" : 3, "title" : "order_id=3,item1", "price" : 21, "num" : 8 } { "_id" : ObjectId("5eec599454173c45e32c1d82"), "order_id" : 3, "title" : "order_id=3,item2", "price" : 22, "num" : 9 } { "_id" : ObjectId("5eec599454173c45e32c1d83"), "order_id" : 3, "title" : "order_id=3,item3", "price" : 23, "num" : 10 } { "_id" : ObjectId("5eec599454173c45e32c1d84"), "order_id" : 3, "title" : "order_id=3,item4", "price" : 24, "num" : 11 } { "_id" : ObjectId("5eec59cc54173c45e32c1d85"), "order_id" : 4, "title" : "order_id=4,item1", "price" : 25, "num" : 11 } { "_id" : ObjectId("5eec59cc54173c45e32c1d86"), "order_id" : 4, "title" : "order_id=4,item2", "price" : 26, "num" : 12 } { "_id" : ObjectId("5eec59cc54173c45e32c1d87"), "order_id" : 4, "title" : "order_id=4,item3", "price" : 27, "num" : 13 } { "_id" : ObjectId("5eec59cc54173c45e32c1d88"), "order_id" : 4, "title" : "order_id=4,item4", "price" : 28, "num" : 14 } { "_id" : ObjectId("5eec59cc54173c45e32c1d89"), "order_id" : 4, "title" : "order_id=4,item5", "price" : 29, "num" : 15 } { "_id" : ObjectId("5eec5a0154173c45e32c1d8a"), "order_id" : 5, "title" : "order_id=5,item1", "price" : 31, "num" : 15 } { "_id" : ObjectId("5eec5a0154173c45e32c1d8b"), "order_id" : 5, "title" : "order_id=5,item2", "price" : 32, "num" : 16 } >
通过 $project 操作符,修改文档的结构,查找 order 只返回 trade_sum 和 all_price字段:
> use order switched to db order > db.order.aggregate([ ... { ... $project:{trade_sum:1,all_price:1} ... } ... ]} 2020-06-19T14:28:37.794+0800 E QUERY [js] uncaught exception: SyntaxError: missing ) after argument list : @(shell):5:1 > db.order.aggregate([ { $project:{trade_sum:1,all_price:1} } ]) { "_id" : ObjectId("5eec580554173c45e32c1d75"), "trade_sum" : 10, "all_price" : 101 } { "_id" : ObjectId("5eec580554173c45e32c1d76"), "trade_sum" : 20, "all_price" : 102 } { "_id" : ObjectId("5eec580554173c45e32c1d77"), "trade_sum" : 30, "all_price" : 103 } { "_id" : ObjectId("5eec580554173c45e32c1d78"), "trade_sum" : 40, "all_price" : 104 } { "_id" : ObjectId("5eec580554173c45e32c1d79"), "trade_sum" : 50, "all_price" : 105 } >
通过$match ,过滤文档,
> db.order.aggregate([ ... { ... $project:{trade_sum:1,all_price:1} ... } ... , ... { ... $match:{all_price:{$gte:103}} ... } ... ]) { "_id" : ObjectId("5eec580554173c45e32c1d77"), "trade_sum" : 30, "all_price" : 103 } { "_id" : ObjectId("5eec580554173c45e32c1d78"), "trade_sum" : 40, "all_price" : 104 } { "_id" : ObjectId("5eec580554173c45e32c1d79"), "trade_sum" : 50, "all_price" : 105 } >
通过 $group 将集合中的文档进行分组,可用于统计结果,统计每个订单的订单数量,按照订单号分组:
> db.orderItem.aggregate( ... [ ... {$group:{ID:"$order_id",total:{$sum:"$num"}} } ... ] ... ) 2020-06-19T14:38:28.146+0800 E QUERY [js] uncaught exception: Error: command failed: { "ok" : 0, "errmsg" : "The field 'ID' must be an accumulator object", "code" : 40234, "codeName" : "Location40234" } : aggregate failed : _getErrorWithCode@src/mongo/shell/utils.js:25:13 doassert@src/mongo/shell/assert.js:18:14 _assertCommandWorked@src/mongo/shell/assert.js:583:17 assert.commandWorked@src/mongo/shell/assert.js:673:16 DB.prototype._runAggregate@src/mongo/shell/db.js:266:5 DBCollection.prototype.aggregate@src/mongo/shell/collection.js:1012:12 @(shell):1:1 > db.orderItem.aggregate( [ {$group:{_id:"$order_id",total:{$sum:"$num"}} } ] ) { "_id" : 2, "total" : 30 } { "_id" : 3, "total" : 38 } { "_id" : 1, "total" : 15 } { "_id" : 5, "total" : 31 } { "_id" : 4, "total" : 65 } >
通过 $sort 将集合中的文档进行排序:
> db.order.aggregate([ ... { ... $project:{trade_sum:1,all_price:1} ... }, ... { ... $match:{all_price:{$gte:104}} ... }, ... { ... $sort:{all_price:-1} ... } ... ]) { "_id" : ObjectId("5eec580554173c45e32c1d79"), "trade_sum" : 50, "all_price" : 105 } { "_id" : ObjectId("5eec580554173c45e32c1d78"), "trade_sum" : 40, "all_price" : 104 } >
¥$limit 限制数量:
> db.order.aggregate([ ... { ... $project:{trade_sum:1,all_price:1} ... }, ... { ... $match:{all_price:{$gte:102}} ... }, ... { ... $sort:{all_price:-1} ... }, ... { ... $limit:2 ... } ... ]) { "_id" : ObjectId("5eec580554173c45e32c1d79"), "trade_sum" : 50, "all_price" : 105 } { "_id" : ObjectId("5eec580554173c45e32c1d78"), "trade_sum" : 40, "all_price" : 104 } >
$skip 跳过某一页,从指定记录开始查询:
> db.order.aggregate([ ... { ... $project:{trade_sum:1,all_price:1} ... }, ... { ... $sort:{all_price:1} ... }, ... { ... $skip:3 ... } ... ]) { "_id" : ObjectId("5eec580554173c45e32c1d78"), "trade_sum" : 40, "all_price" : 104 } { "_id" : ObjectId("5eec580554173c45e32c1d79"), "trade_sum" : 50, "all_price" : 105 } >
$lookup 表关联:
> show dbs admin 0.000GB config 0.000GB hello 0.000GB local 0.000GB > use hello switched to db hello > show collections order orderItem user > db.order.find() { "_id" : ObjectId("5eec63141f939bf9cce25f7b"), "order_id" : 1, "trade_sum" : 101, "all_price" : 100, "all_num" : 11 } { "_id" : ObjectId("5eec63141f939bf9cce25f7c"), "order_id" : 2, "trade_sum" : 102, "all_price" : 200, "all_num" : 12 } { "_id" : ObjectId("5eec63141f939bf9cce25f7d"), "order_id" : 3, "trade_sum" : 103, "all_price" : 300, "all_num" : 13 } { "_id" : ObjectId("5eec63141f939bf9cce25f7e"), "order_id" : 4, "trade_sum" : 104, "all_price" : 400, "all_num" : 14 } { "_id" : ObjectId("5eec63141f939bf9cce25f7f"), "order_id" : 5, "trade_sum" : 105, "all_price" : 500, "all_num" : 15 } > db.orderItem.find() { "_id" : ObjectId("5eec638c1f939bf9cce25f80"), "order_id" : 1, "title" : "orderId=1,from item1", "price" : 10, "num" : 6 } { "_id" : ObjectId("5eec638c1f939bf9cce25f81"), "order_id" : 1, "title" : "orderId=1,from item2", "price" : 20, "num" : 7 } { "_id" : ObjectId("5eec638c1f939bf9cce25f82"), "order_id" : 1, "title" : "orderId=1,from item3", "price" : 30, "num" : 8 } { "_id" : ObjectId("5eec63c71f939bf9cce25f83"), "order_id" : 2, "title" : "orderId=2,from item1", "price" : 12, "num" : 11 } { "_id" : ObjectId("5eec63c71f939bf9cce25f84"), "order_id" : 2, "title" : "orderId=2,from item2", "price" : 24, "num" : 12 } { "_id" : ObjectId("5eec63c71f939bf9cce25f85"), "order_id" : 2, "title" : "orderId=2,from item3", "price" : 36, "num" : 13 } { "_id" : ObjectId("5eec63f41f939bf9cce25f86"), "order_id" : 3, "title" : "orderId=3,from item1", "price" : 15, "num" : 18 } { "_id" : ObjectId("5eec63f41f939bf9cce25f87"), "order_id" : 3, "title" : "orderId=3,from item2", "price" : 30, "num" : 19 } { "_id" : ObjectId("5eec63f41f939bf9cce25f88"), "order_id" : 3, "title" : "orderId=3,from item3", "price" : 45, "num" : 20 } { "_id" : ObjectId("5eec63f41f939bf9cce25f89"), "order_id" : 3, "title" : "orderId=3,from item4", "price" : 60, "num" : 21 } { "_id" : ObjectId("5eec63f41f939bf9cce25f8a"), "order_id" : 3, "title" : "orderId=3,from item5", "price" : 75, "num" : 22 } { "_id" : ObjectId("5eec64241f939bf9cce25f8b"), "order_id" : 4, "title" : "orderId=4,from item1", "price" : 20, "num" : 28 } { "_id" : ObjectId("5eec64241f939bf9cce25f8c"), "order_id" : 4, "title" : "orderId=4,from item2", "price" : 40, "num" : 29 } { "_id" : ObjectId("5eec644b1f939bf9cce25f8d"), "order_id" : 5, "title" : "orderId=5,from item1", "price" : 24, "num" : 33 } { "_id" : ObjectId("5eec644b1f939bf9cce25f8e"), "order_id" : 5, "title" : "orderId=5,from item2", "price" : 48, "num" : 34 } { "_id" : ObjectId("5eec644b1f939bf9cce25f8f"), "order_id" : 5, "title" : "orderId=5,from item3", "price" : 72, "num" : 35 } { "_id" : ObjectId("5eec644b1f939bf9cce25f90"), "order_id" : 5, "title" : "orderId=5,from item4", "price" : 96, "num" : 36 } > db.order.aggregate([ ... { ... $lookup:{ ... from:"orderItem", ... localField:"order_id", ... foreignField:"order_id", ... as:"items" ... } ... } ... ]) { "_id" : ObjectId("5eec63141f939bf9cce25f7b"), "order_id" : 1, "trade_sum" : 101, "all_price" : 100, "all_num" : 11,
"items" : [ { "_id" : ObjectId("5eec638c1f939bf9cce25f80"), "order_id" : 1, "title" : "orderId=1,from item1", "price" : 10, "num" : 6 },
{ "_id" : ObjectId("5eec638c1f939bf9cce25f81"), "order_id" : 1, "title" : "orderId=1,from item2", "price" : 20, "num" : 7 },
{ "_id" : ObjectId("5eec638c1f939bf9cce25f82"), "order_id" : 1, "title" : "orderId=1,from item3", "price" : 30, "num" : 8 }
] } { "_id" : ObjectId("5eec63141f939bf9cce25f7c"), "order_id" : 2, "trade_sum" : 102, "all_price" : 200, "all_num" : 12,
"items" : [ { "_id" : ObjectId("5eec63c71f939bf9cce25f83"), "order_id" : 2, "title" : "orderId=2,from item1", "price" : 12, "num" : 11 },
{ "_id" : ObjectId("5eec63c71f939bf9cce25f84"), "order_id" : 2, "title" : "orderId=2,from item2", "price" : 24, "num" : 12 },
{ "_id" : ObjectId("5eec63c71f939bf9cce25f85"), "order_id" : 2, "title" : "orderId=2,from item3", "price" : 36, "num" : 13 }
] } { "_id" : ObjectId("5eec63141f939bf9cce25f7d"), "order_id" : 3, "trade_sum" : 103, "all_price" : 300, "all_num" : 13,
"items" : [ { "_id" : ObjectId("5eec63f41f939bf9cce25f86"), "order_id" : 3, "title" : "orderId=3,from item1", "price" : 15, "num" : 18 },
{ "_id" : ObjectId("5eec63f41f939bf9cce25f87"), "order_id" : 3, "title" : "orderId=3,from item2", "price" : 30, "num" : 19 },
{ "_id" : ObjectId("5eec63f41f939bf9cce25f88"), "order_id" : 3, "title" : "orderId=3,from item3", "price" : 45, "num" : 20 },
{ "_id" : ObjectId("5eec63f41f939bf9cce25f89"), "order_id" : 3, "title" : "orderId=3,from item4", "price" : 60, "num" : 21 },
{ "_id" : ObjectId("5eec63f41f939bf9cce25f8a"), "order_id" : 3, "title" : "orderId=3,from item5", "price" : 75, "num" : 22 }
] } { "_id" : ObjectId("5eec63141f939bf9cce25f7e"), "order_id" : 4, "trade_sum" : 104, "all_price" : 400, "all_num" : 14,
"items" : [ { "_id" : ObjectId("5eec64241f939bf9cce25f8b"), "order_id" : 4, "title" : "orderId=4,from item1", "price" : 20, "num" : 28 },
{ "_id" : ObjectId("5eec64241f939bf9cce25f8c"), "order_id" : 4, "title" : "orderId=4,from item2", "price" : 40, "num" : 29 }
] } { "_id" : ObjectId("5eec63141f939bf9cce25f7f"), "order_id" : 5, "trade_sum" : 105, "all_price" : 500, "all_num" : 15,
"items" : [ { "_id" : ObjectId("5eec644b1f939bf9cce25f8d"), "order_id" : 5, "title" : "orderId=5,from item1", "price" : 24, "num" : 33 },
{ "_id" : ObjectId("5eec644b1f939bf9cce25f8e"), "order_id" : 5, "title" : "orderId=5,from item2", "price" : 48, "num" : 34 },
{ "_id" : ObjectId("5eec644b1f939bf9cce25f8f"), "order_id" : 5, "title" : "orderId=5,from item3", "price" : 72, "num" : 35 },
{ "_id" : ObjectId("5eec644b1f939bf9cce25f90"), "order_id" : 5, "title" : "orderId=5,from item4", "price" : 96, "num" : 36 }
] } >