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

MongoDB聚合查询:多数组对象的$lookup关联实现问题

解决MongoDB中关联数组元素并保留对应quantity的问题

问题场景

assemblies集合文档结构如下:

assemblies: { 
  mechanicalItems: [{ 
    mechanicalId: ObjectId("xxx"), // 关联mechanicalitems集合
    quantity: 5
  }],
  electricalItems: [{ 
    mechanicalId: ObjectId("yyy"), // 关联electricalitems集合
    quantity: 3
  }]
}

需要将数组中的mechanicalId替换为对应集合的完整文档,同时保留原quantity字段,期望输出:

assemblies: {
  mechanicalItems: [{
    item: {
      _id: ObjectId("xxx"),
      size: '12',
      material: 'steel',
      style: 'thick'
    },
    quantity: 5
 }, ...],
 electricalItems: [{
    item: {
      _id: ObjectId("yyy"),
      current: '15',
      rating: 'low voltage',
      insulation: 'PVC'
    },
    quantity: 3
  }, ...]
}

原尝试的$lookup会导致quantity变成数组,使用unwind+group又会丢失另一个数组。

解决方案

方案一:拆分-关联-聚合回原结构(兼容低版本MongoDB)

通过分步骤处理每个数组,拆分后关联再聚合,同时保留其他数组字段:

db.assemblies.aggregate([
  // 处理mechanicalItems数组
  { $unwind: "$mechanicalItems" },
  {
    $lookup: {
      from: "mechanicalitems",
      localField: "mechanicalItems.mechanicalId",
      foreignField: "_id",
      as: "mechanicalItems.item"
    }
  },
  { $unwind: "$mechanicalItems.item" },
  {
    $group: {
      _id: "$_id",
      mechanicalItems: { $push: "$mechanicalItems" },
      electricalItems: { $first: "$electricalItems" },
      // 保留assemblies其他原始字段,按需添加
      name: { $first: "$name" },
      createTime: { $first: "$createTime" }
    }
  },
  // 处理electricalItems数组
  { $unwind: "$electricalItems" },
  {
    $lookup: {
      from: "electricalitems",
      localField: "electricalItems.mechanicalId",
      foreignField: "_id",
      as: "electricalItems.item"
    }
  },
  { $unwind: "$electricalItems.item" },
  {
    $group: {
      _id: "$_id",
      electricalItems: { $push: "$electricalItems" },
      mechanicalItems: { $first: "$mechanicalItems" },
      name: { $first: "$name" },
      createTime: { $first: "$createTime" }
    }
  },
  // 清理冗余字段
  {
    $project: {
      "mechanicalItems.mechanicalId": 0,
      "electricalItems.mechanicalId": 0
    }
  }
])

步骤说明

  1. 拆分数组:用$unwind将目标数组拆分为单个元素文档,便于逐个关联。
  2. 关联集合:通过localField指定当前元素的mechanicalId,匹配对应集合的文档,结果存入item字段。
  3. 展开关联结果:$unwind将lookup返回的单元素数组转为对象格式。
  4. 聚合回原结构:$group按文档_id分组,用$push重新组装目标数组,用$first保留其他数组和原始字段。
  5. 清理冗余:用$project移除不再需要的mechanicalId字段。

方案二:用子管道匹配对应quantity(MongoDB 3.6+)

利用$indexOfArray和$arrayElemAt直接匹配数组中对应元素的quantity,避免拆分聚合操作:

db.assemblies.aggregate([
  // 处理mechanicalItems
  {
    $lookup: {
      from: "mechanicalitems",
      let: { originItems: "$mechanicalItems" },
      pipeline: [
        {
          $match: {
            $expr: { $in: ["$_id", "$$originItems.mechanicalId"] }
          }
        },
        {
          $addFields: {
            quantity: {
              $arrayElemAt: [
                "$$originItems.quantity",
                { $indexOfArray: ["$$originItems.mechanicalId", "$_id"] }
              ]
            }
          }
        },
        {
          $project: {
            item: "$$ROOT",
            quantity: 1
          }
        }
      ],
      as: "mechanicalItems"
    }
  },
  // 处理electricalItems
  {
    $lookup: {
      from: "electricalitems",
      let: { originItems: "$electricalItems" },
      pipeline: [
        {
          $match: {
            $expr: { $in: ["$_id", "$$originItems.mechanicalId"] }
          }
        },
        {
          $addFields: {
            quantity: {
              $arrayElemAt: [
                "$$originItems.quantity",
                { $indexOfArray: ["$$originItems.mechanicalId", "$_id"] }
              ]
            }
          }
        },
        {
          $project: {
            item: "$$ROOT",
            quantity: 1
          }
        }
      ],
      as: "electricalItems"
    }
  },
  // 调整最终结构
  {
    $addFields: {
      mechanicalItems: {
        $map: {
          input: "$mechanicalItems",
          as: "mi",
          in: {
            item: { $mergeObjects: ["$$mi.item", { _id: "$$mi.item._id" }] },
            quantity: "$$mi.quantity"
          }
        }
      },
      electricalItems: {
        $map: {
          input: "$electricalItems",
          as: "ei",
          in: {
            item: { $mergeObjects: ["$$ei.item", { _id: "$$ei.item._id" }] },
            quantity: "$$ei.quantity"
          }
        }
      }
    }
  }
])

步骤说明

  1. 批量匹配关联文档:用$in匹配所有关联的文档ID。
  2. 匹配对应quantity:通过$indexOfArray找到当前文档_id在原数组中的位置,再用$arrayElemAt取出对应位置的quantity。
  3. 调整结构:用$map重新组装数组元素,得到期望的item+quantity格式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 07:59:59