如何在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 } ]
原代码问题分析
你尝试的代码存在两个关键错误:
- $set用法错误:
$set需要接收键值对形式的字段映射,不能直接将$cond作为$set的整体值,MongoDB无法解析这种结构。 - 字段名语法错误: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
相关产品推荐
相关产品推荐

