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

MongoDB聚合:展示包含父文档信息的所有子文档

MongoDB聚合:为子文档添加父文档字段

集合结构

[
  {
    inv_name: "Client 1",
    inv_date: 2022-12-20T05:09:09.803Z,
    inv_ready: false,
    inv_payments: [
      {
        id: "123",
        pay_amount: 32.45
      },
      {
        id: "456",
        pay_amount: 55.60
      }
    ]
  },
  {
    inv_name: "Client 2",
    inv_date: 2022-12-19T05:09:09.803Z,
    inv_ready: true,
    inv_payments: [
      {
        id: "459",
        pay_amount: 67.45
      },
      {
        id: "556",
        pay_amount: 30.60
      }
    ]
  }
]

目标结果

提取每个inv_payments子文档,添加父文档的inv_name作为client字段,同时将子文档的id重命名为pay_date,最终输出:

[
  {
    "client": "Client 1",
    "pay_amount": 32.45,
    "pay_date": "123"
  },
  {
    "client": "Client 1",
    "pay_amount": 55.6,
    "pay_date": "456"
  },
  {
    "client": "Client 2",
    "pay_amount": 67.45,
    "pay_date": "459"
  },
  {
    "client": "Client 2",
    "pay_amount": 30.6,
    "pay_date": "556"
  }
]

尝试的聚合代码

db.invoices.aggregate([
  {
    "$project": {
      _id: 0,
      "inv_payments": {
        $reduce: {
          input: "$inv_payments",
          initialValue: [],
          in: {
            $concatArrays: [
              [
                {
                  client: "$this.name",
                  pay_id: "$$this.id",
                  pay_amount: "$$this.pay_amount"
                }
              ],
              "$inv_payments"
            ]
          }
        }
      }
    }
  },
  {
    $unwind: "$inv_payments"
  },
  {
    $replaceRoot: {
      newRoot: "$inv_payments"
    }
  }
])

问题分析与修正方案

你的代码存在3个核心问题:

  1. $reduce逻辑错误:每次循环都拼接原始$inv_payments数组,会导致无限重复,且未使用$reduce的累加器$$value来构建结果数组。
  2. 字段引用错误:父文档的客户名字段是inv_name,不是$this.name,正确引用应为$inv_name。
  3. 字段命名不符:目标结果需要pay_date,但代码中写的是pay_id。

以下是两种更简洁的可行方案:

方案一:$unwind + $project(最直接)

db.invoices.aggregate([
  // 展开inv_payments数组,将每个子文档转为独立文档
  { $unwind: "$inv_payments" },
  // 投影并重构字段,关联父文档信息
  {
    $project: {
      _id: 0,
      client: "$inv_name",
      pay_amount: "$inv_payments.pay_amount",
      pay_date: "$inv_payments.id"
    }
  }
])

方案二:$map处理数组 + $unwind + $replaceRoot

如果希望先在数组内完成字段重构再展开:

db.invoices.aggregate([
  {
    $project: {
      _id: 0,
      payments: {
        $map: {
          input: "$inv_payments",
          as: "pay",
          in: {
            client: "$inv_name",
            pay_amount: "$$pay.pay_amount",
            pay_date: "$$pay.id"
          }
        }
      }
    }
  },
  { $unwind: "$payments" },
  { $replaceRoot: { newRoot: "$payments" } }
])

两种方案都能精准输出目标结果,逻辑比$reduce更清晰,适配你的需求场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 00:25:20