You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用$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" }
])

步骤说明

  1. $unwind:将父文档的votes数组拆分为多个独立文档,每个文档包含原父文档的其他字段和单个votes元素,这样才能逐个关联对应的投票信息。
  2. $lookup:通过votes.voteId与registration集合的voteId匹配,把对应的投票文档存入voteInfo数组(由于是一对一匹配,数组仅含一个元素)。
  3. $addFields:使用$mergeObjects将原有votes字段和voteInfo的第一个元素合并,既保留原有字段,又添加投票集合的字段。
  4. $unset:删除临时生成的voteInfo字段,清理冗余数据。
  5. $group:按照parentId重新分组,将拆分后的votes元素重新组合成数组,恢复父文档的原始结构。
  6. $unset:可选操作,移除聚合过程中自动生成的_id字段,让最终结果与期望结构完全一致。

内容的提问来源于stack exchange,提问作者stackoverfloweth

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 00:47:22