MongoDB带Pipeline的$lookup匹配数组对象布尔值与OID问题
MongoDB聚合查询$lookup关联过滤问题解决
需求说明
对Items集合执行聚合查询并关联Partners集合,为每个Item文档添加partners字段,其值为Partners集合中满足以下条件的文档列表:
- 文档的
supportedCategories数组中存在元素,该元素的category与Item的category匹配 - 该元素的
active字段为true
集合结构示例
Items集合文档
let item = { // 其他字段 category: ObjectId('A') }
Partners集合文档
let partner = { // 其他字段 supportedCategories: [{ category: ObjectId('A'), active: true }, ...] }
遇到的问题
- 无Pipeline的$lookup:仅能匹配category的ObjectId,无法过滤
active: true的条件,代码如下:
{ $lookup: { from: 'partners', localField: 'category', foreignField: 'supportedCategories.category', as: 'joinedPartners', }, }
- 带Pipeline的$lookup:硬编码ObjectId时
active: true过滤有效,但使用let定义的$$mycat变量无法匹配category,代码如下:
{ $lookup: { from: "partners", let: { mycat: "$category" }, pipeline: [ { $match: { supportedCategories: { $elemMatch: { category: '$$mycat', active: true } } }, }, ], as: "joinedPartners" } }
问题原因
普通的$match查询条件(未包裹在$expr中)无法访问聚合阶段通过let定义的变量(如$$mycat),只有在$expr上下文内才能引用这些聚合变量。
解决方案
将$match中的条件包裹在$expr中,使用$elemMatch结合聚合变量进行过滤,修正后的代码如下:
{ $lookup: { from: "partners", let: { mycat: "$category" }, pipeline: [ { $match: { $expr: { $elemMatch: { input: "$supportedCategories", cond: { $and: [ { $eq: ["$$this.category", "$$mycat"] }, { $eq: ["$$this.active", true] } ] } } } } } ], as: "joinedPartners" } }
或者使用$anyElementTrue + $map的等价写法:
{ $lookup: { from: "partners", let: { mycat: "$category" }, pipeline: [ { $match: { $expr: { $anyElementTrue: { $map: { input: "$supportedCategories", as: "sc", in: { $and: [ { $eq: ["$$sc.category", "$$mycat"] }, { $eq: ["$$sc.active", true] } ] } } } } } } ], as: "joinedPartners" } }
内容的提问来源于stack exchange,提问作者Sebastian Picchio
相关产品推荐
相关产品推荐

