Mongo聚合查询优化:不使用$expr实现Lookup内数组匹配
解决MongoDB聚合中避免使用$expr实现多对多关系的成本汇总
你的问题根源在于:$lookup子管道里的普通$match条件不能直接引用let定义的变量,必须用$expr才能访问$$resources_ids,但$expr会让查询跳过索引,拖慢性能。
原来的写法是先按rule_id分组得到资源ID数组,再通过子管道匹配数组内的资源,这种逻辑绕不开$expr,但完全可以换一种思路优化:
优化方案(无需$expr,充分利用索引)
调整聚合顺序,先关联成本数据再分组汇总:
db.collection.aggregate([ // 用传统lookup关联,自动利用cost_data.resource_id索引 { $lookup: { from: "cost_data", localField: "resource_id", foreignField: "resource_id", as: "cost_info" } }, // 展开成本数据(单个resource对应多条cost时必须,单条可省略) { $unwind: "$cost_info" }, // 按rule_id分组,汇总总成本 { $group: { _id: "$rule_id", rule_id: { $first: "$rule_id" }, total_cost: { $sum: "$cost_info.cost" } } } ])
为什么这个方案可行?
- 索引利用:传统
$lookup的localField/foreignField匹配逻辑,MongoDB会自动使用cost_data集合上的resource_id索引,比子管道里的$expr+$in快得多。 - 逻辑简化:直接把每个规则下的资源成本关联后再聚合,不需要先分组生成资源数组,完全避开了
$expr的使用。
补充说明
如果cost_data中每个resource_id只有一条成本记录,可以去掉$unwind阶段,直接在$group里写:
total_cost: { $sum: { $first: "$cost_info.cost" } }
或者直接$sum: "$cost_info.cost",因为单元素数组会自动取值。
内容的提问来源于stack exchange,提问作者madarinho
相关产品推荐
相关产品推荐

