如何使用$lookup按外键关联子数组并保留原字段?
MongoDB 关联子文档并保留原有字段的实现方法
需求场景
父文档结构:
{ parentId: string, votes: [ { voteId: string, something: number } ] }
投票文档结构(存储在registration集合):
{ voteId: string, name: string }
期望结果:保留父文档votes数组中每个元素的原有字段(voteId、something),同时合并对应投票文档的字段(name等),最终结构如下:
{ parentId: string, votes: [ { voteId: string, something: number, name: string } ] }
之前尝试的空管道$lookup会直接覆盖原有votes字段,导致丢失something等信息,无法满足需求。
正确实现方案
通过聚合管道的多步骤操作来实现,具体代码如下:
db.parentCollection.aggregate([ // 拆分votes数组,每个元素转为独立文档 { $unwind: "$votes" }, // 根据voteId关联投票集合 { $lookup: { from: "registration", localField: "votes.voteId", foreignField: "voteId", as: "voteInfo" } }, // 合并原有votes字段与投票信息 { $addFields: { "votes": { $mergeObjects: [ "$votes", { $arrayElemAt: [ "$voteInfo", 0 ] } ] } } }, // 清理临时字段 { $unset: "voteInfo" }, // 重新分组恢复数组结构 { $group: { _id: "$parentId", parentId: { $first: "$parentId" }, votes: { $push: "$votes" } } }, // 移除自动生成的_id(可选) { $unset: "_id" } ])
步骤说明
- $unwind:将父文档的
votes数组拆分为多个独立文档,每个文档包含原父文档的其他字段和单个votes元素,这样才能逐个关联对应的投票信息。 - $lookup:通过
votes.voteId与registration集合的voteId匹配,把对应的投票文档存入voteInfo数组(由于是一对一匹配,数组仅含一个元素)。 - $addFields:使用
$mergeObjects将原有votes字段和voteInfo的第一个元素合并,既保留原有字段,又添加投票集合的字段。 - $unset:删除临时生成的
voteInfo字段,清理冗余数据。 - $group:按照
parentId重新分组,将拆分后的votes元素重新组合成数组,恢复父文档的原始结构。 - $unset:可选操作,移除聚合过程中自动生成的
_id字段,让最终结果与期望结构完全一致。
内容的提问来源于stack exchange,提问作者stackoverfloweth
相关产品推荐
相关产品推荐

