MongoDB 3.2如何实现保留库存的关联查询?含订单匹配场景
解决MongoDB关联集合时保留所有主集合记录的问题
你的需求是获取所有inventory记录,同时仅关联orders中coin_id匹配且user_id=11的订单——但当前的聚合代码会过滤掉没有匹配订单的inventory文档,原因很简单:
你在
$lookup之后直接用$match过滤coin_details.user_id='11',当coin_details是空数组(没有匹配订单)或者数组里没有符合user_id=11的元素时,整个inventory文档会被直接排除,这就违背了“保留所有inventory记录”的要求。
下面针对MongoDB 3.2环境给出正确实现,同时提供更高版本的优化方案:
方案一:MongoDB 3.2 兼容实现
因为3.2版本的$lookup仅支持简单等值关联,我们需要先关联所有匹配coin_id的订单,再用$filter操作符过滤出符合user_id=11的订单,同时保留所有inventory记录:
db.inventory.aggregate([ { $lookup: { from: 'orders', localField: 'coin_id', foreignField: 'coin_id', as: 'coin_details' } }, { $project: { _id: 1, coin_id: 1, description: 1, coin_details: { $filter: { input: "$coin_details", as: "item", cond: { $eq: ["$$item.user_id", 11] } } } } } ])
逻辑说明:
$lookup先把所有coin_id匹配的订单关联到coin_details数组中$project里用$filter遍历coin_details数组,只保留user_id=11的元素;如果没有符合条件的元素,coin_details会是空数组,但inventory的核心字段依然会完整返回
方案二:MongoDB 3.6+ 优化实现
如果你能升级到MongoDB 3.6或更高版本,可以直接在$lookup中使用子管道(pipeline),在关联阶段就过滤掉不符合条件的订单,减少不必要的数据传输,性能更优:
db.inventory.aggregate([ { $lookup: { from: "orders", let: { inv_coin_id: "$coin_id" }, pipeline: [ { $match: { $expr: { $and: [ { $eq: ["$coin_id", "$$inv_coin_id"] }, { $eq: ["$user_id", 11] } ] } } } ], as: "coin_details" } } ])
逻辑说明:
let定义了一个变量inv_coin_id,存储当前inventory文档的coin_id- 子管道中的
$match通过$expr引用变量,同时匹配coin_id等值和user_id=11的条件,直接只关联符合要求的订单,避免后续过滤操作
内容的提问来源于stack exchange,提问作者Sarus Crane
相关产品推荐
相关产品推荐

