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

如何在MongoDB中展平对象并按条件重命名字段至根层级

MongoDB 展平balance对象并按documentType重命名字段

需求说明

现有集合数据结构如下:

[
  {
    "id": "1234",
    "documentType": "IV",
    "balance": {
      "total": 100,
      "openBalance": 60,
      "paid": 40
    }
  },  
  {
    "id": "9012",
    "documentType": "CM",
    "balance": {
      "total": 50,
      "applied": 0,
      "available": 50
    }
  }
]

需要实现:

  • 展平balance对象,将其字段提升到根层级
  • 根据documentType重命名字段:
    • 当documentType = "IV"时,balance.paid重命名为totalAmountPaid
    • 当documentType = "CM"时,balance.applied重命名为appliedAmount,balance.available重命名为availableAmount

最终目标结构:

[
  {
    "id": "1234",
    "documentType": "IV",
    "total": 100,
    "openBalance": 60,
    "totalAmountPaid": 40
  },  
  {
    "id": "9012",
    "documentType": "CM",
    "total": 50,
    "appliedAmount": 0,
    "availableAmount": 50
  }
]

原代码问题分析

你尝试的代码存在两个关键错误:

  1. $set用法错误:$set需要接收键值对形式的字段映射,不能直接将$cond作为$set的整体值,MongoDB无法解析这种结构。
  2. 字段名语法错误:else分支中的字段名错误添加了$前缀,这会被MongoDB识别为字段路径而非新字段名,导致语法报错。

正确解决方案

方案1:分字段设置+移除balance

通过$set逐个字段赋值,用$cond控制不同类型的字段取值,最后用$unset移除原balance字段:

db.collection.aggregate([
  {
    $set: {
      // 所有类型都保留total字段
      total: "$balance.total",
      // 仅IV类型保留openBalance
      openBalance: {
        $cond: {
          if: { $eq: ["$documentType", "IV"] },
          then: "$balance.openBalance",
          else: "$$REMOVE"
        }
      },
      // 仅IV类型添加totalAmountPaid
      totalAmountPaid: {
        $cond: {
          if: { $eq: ["$documentType", "IV"] },
          then: "$balance.paid",
          else: "$$REMOVE"
        }
      },
      // 仅CM类型添加appliedAmount
      appliedAmount: {
        $cond: {
          if: { $eq: ["$documentType", "CM"] },
          then: "$balance.applied",
          else: "$$REMOVE"
        }
      },
      // 仅CM类型添加availableAmount
      availableAmount: {
        $cond: {
          if: { $eq: ["$documentType", "CM"] },
          then: "$balance.available",
          else: "$$REMOVE"
        }
      }
    }
  },
  // 移除原balance字段
  { $unset: "balance" }
])

方案2:用$replaceRoot合并文档

通过$replaceRoot结合$mergeObjects,一次性将原有文档、处理后的balance字段合并,并移除原balance字段,代码更简洁:

db.collection.aggregate([
  {
    $replaceRoot: {
      newRoot: {
        $mergeObjects: [
          // 保留原有根文档的所有字段
          "$$ROOT",
          // 根据documentType生成对应的字段映射
          {
            $cond: [
              { $eq: ["$documentType", "IV"] },
              {
                total: "$balance.total",
                openBalance: "$balance.openBalance",
                totalAmountPaid: "$balance.paid"
              },
              {
                total: "$balance.total",
                appliedAmount: "$balance.applied",
                availableAmount: "$balance.available"
              }
            ]
          },
          // 移除原balance字段
          { balance: "$$REMOVE" }
        ]
      }
    }
  }
])

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 16:53:35