MongoDB 3.2中使用Aggregate与$lookup匹配数组值的问题
没问题,我来帮你搞定这个MongoDB跨集合关联的需求!针对你在MongoDB 3.2中要通过数组字段关联两个集合的场景,我们可以用$unwind+$lookup+$group的组合来实现,具体方案如下:
实现数组字段的跨集合关联查询
完整聚合管道代码
db.foos.aggregate([ // 第一步:拆分barKey数组,将每个数组元素转为独立文档 { $unwind: "$barKey" }, // 第二步:关联bars集合,匹配对应barKey字段 { $lookup: { from: "bars", localField: "barKey", foreignField: "barKey", as: "matchedBars" } }, // 第三步:按原文档_id分组,恢复原结构并合并匹配结果 { $group: { _id: "$_id", fooProp: { $first: "$fooProp" }, barKey: { $addToSet: "$barKey" }, matchedBars: { $addToSet: { $arrayElemAt: ["$matchedBars", 0] } } } }, // 可选:过滤空匹配结果,整理输出格式 { $project: { _id: 1, fooProp: 1, barKey: 1, matchedBars: { $filter: { input: "$matchedBars", as: "bar", cond: { $ne: ["$$bar", null] } } } } } ])
代码分步解释
$unwind: "$barKey":把foos文档中的barKey数组拆分成多个独立文档,比如原文档会被拆成两个子文档,分别携带barKey: "key1"和barKey: "key2"。这一步是为了适配MongoDB 3.2版本$lookup只能单值匹配的限制。$lookup:关联bars集合,用拆分后的单个barKey值匹配bars集合的barKey字段,匹配到的结果会存入matchedBars数组。$group:按原文档的_id重新分组,恢复原文档结构:$first: "$fooProp":保留原文档的fooProp字段(分组后所有子文档的该字段值一致)$addToSet: "$barKey":把拆分的barKey元素重新组合成数组(自动去重,适合原数组无重复元素的场景)$arrayElemAt: ["$matchedBars", 0]:取出$lookup返回数组中的第一个元素(每个子文档只会匹配到一个bars文档),再用$addToSet合并成完整的匹配结果数组。
- 可选的
$project:过滤掉可能存在的空匹配结果(比如某个barKey在bars集合中无对应文档的情况),让输出的matchedBars数组更整洁。
最终输出结果
执行上述聚合后,你会得到如下格式的文档:
{ "_id": "foo1", "fooProp": "some prop", "barKey": ["key1", "key2"], "matchedBars": [ { "_id": "bar1", "barKey": "key1", "barProp": "some prop 2" }, { "_id": "bar2", "barKey": "key2", "barProp": "some prop 3" } ] }
注意事项
- 如果你需要保留原
barKey数组中的重复元素,可以把$group里的$addToSet换成$push。 - MongoDB 3.2版本的
$lookup不支持直接用数组做匹配,更高版本可以用$lookup的管道语法简化操作,但针对3.2版本,上述方案是最稳妥的实现方式。
内容的提问来源于stack exchange,提问作者MattSidor
相关产品推荐
相关产品推荐

