MongoDB如何将数组元素转换为文档新字段?
解决MongoDB数组元素转扁平字段的问题
问题原因
你的聚合管道返回全null,是因为$parents.relationship会返回一个数组(例如["father", "mother"]),直接用$eq和单个字符串"father"比较永远不成立,所以所有$cond分支都走到了else: null。
方案一:固定关系场景(明确father/mother)
适合已知需要提取的关系类型,步骤清晰易读:
[ { $project: { _id: 0, name: 1, // 筛选并提取父亲对象 father: { $arrayElemAt: [{ $filter: { input: "$parents", cond: { $eq: ["$$this.relationship", "father"] } } }, 0] }, // 筛选并提取母亲对象 mother: { $arrayElemAt: [{ $filter: { input: "$parents", cond: { $eq: ["$$this.relationship", "mother"] } } }, 0] } } }, { $project: { name: 1, father_name: "$father.name", father_age: "$father.age", mother_name: "$mother.name", mother_age: "$mother.age" } } ]
逻辑说明:
- 第一个
$project阶段:用$filter从parents数组中筛选出对应关系的对象,再用$arrayElemAt取数组第一个元素(确保拿到单个对象)。 - 第二个
$project阶段:将提取出的对象字段拆分为扁平的新字段。
方案二:动态关系场景(支持扩展更多关系)
如果后续可能新增其他关系类型(如grandfather),这个方法无需修改代码即可自动生成对应字段:
[ { $project: { _id: 0, name: 1, parents_flat: { $reduce: { input: "$parents", initialValue: {}, in: { $mergeObjects: [ "$$value", { {$concat: ["$$this.relationship", "_name"]}: "$$this.name", {$concat: ["$$this.relationship", "_age"]}: "$$this.age" } ] } } } } }, { $replaceRoot: { newRoot: { $mergeObjects: ["$$ROOT", "$parents_flat"] } } }, { $project: { parents_flat: 0 } } ]
逻辑说明:
$reduce遍历parents数组,每次将当前对象的name和age拼接为{关系}_name、{关系}_age格式的字段,并用$mergeObjects合并到临时对象中。$replaceRoot将临时对象的字段与原文档的name合并为根文档。- 最后移除临时的
parents_flat字段。
最终输出
两种方案都能得到你预期的扁平结构:
{"name": "person1", "father_name": "father1", "father_age": 40, "mother_name": "mother1", "mother_age": 42} {"name": "person2", "father_name": "father2", "father_age": 50, "mother_name": "mother2", "mother_age": 45}
内容的提问来源于stack exchange,提问作者sbrunch
相关产品推荐
相关产品推荐

