MongoDB:无需$lookup匹配嵌套文档数组与对应值的方法
问题描述
我的文档结构如下:
{ ... problems: [ { ... id: 1, ...}, { ... id: 7, ...}, { ... id: 122, ...} ], solutions: [ { ... assignedProblems: [1, 7] ... }, { ... assignedProblems: [122] ...} ], ... }
需要将solutions中的assignedProblems数组,与同文档内problems数组的id进行匹配关联。
当前使用的聚合操作虽然能正常运行,但即使添加索引后性能依然极差:
{ $unwind: { path: "$solutions" }, $lookup: { from: "problems", localField: "solutions.assignedProblems", foreignField: "id", as: "problems" } }
曾尝试用$match替代$lookup,但$setEquals和$eq仅在两边数组元素数量完全一致时生效:
$match: { $expr: { $setEquals: ["$solutions.assignedProblems", "$problems.id"] } }
请问有没有其他方法可以实现这种id数组与内部文档数组的匹配,避免低效的$lookup?
解决方案
可以利用MongoDB的数组操作符在单文档内完成匹配,无需跨集合的$lookup,具体步骤如下:
- 先用
$unwind拆分solutions数组,逐个处理每个solution项 - 使用
$filter从当前文档的problems数组中,筛选出id存在于assignedProblems中的元素
完整聚合示例:
[ { $unwind: "$solutions" }, { $addFields: { "solutions.matchedProblems": { $filter: { input: "$problems", cond: { $in: ["$$this.id", "$solutions.assignedProblems"] } } } } }, // 可选步骤:如果需要将solutions重新组合为数组,添加以下$group操作 { $group: { _id: "$_id", problems: { $first: "$problems" }, solutions: { $push: "$solutions" }, // 保留其他需要的字段,根据字段类型选择$first或对应操作符 otherField: { $first: "$otherField" } } } ]
关键说明
$filter完全在单文档内处理数据,不会产生跨集合查询的开销,性能远优于$lookup- 如果不需要保留
solutions的数组结构,可以跳过最后的$group步骤 - 无需额外创建索引,仅依赖单文档内的数组遍历匹配
内容的提问来源于stack exchange,提问作者abit
相关产品推荐
相关产品推荐

