MongoDB 4.4中基于复合键合并/分组文档的聚合方案求助
MongoDB聚合管道实现文档分组合并需求
需求说明
通过MongoDB聚合管道,按机器编号(MACHINE.NUMBER)、**机器型号(MACHINE.MACHINE_MODEL)和许可证编号(LICENSE.NUMBER)**的关联关系分组合并文档,最终输出到新集合。需实现:
- 合并同一分组下的
INFO字段为数组(单条时转为字符串) - 对
MACHINE和LICENSE数组去重,保留唯一条目
集合示例文档
[ { "INFO": "A", "MACHINE": [ { "NUMBER": "0001", "MACHINE_MODEL": "A001" }, { "NUMBER": "0002", "MACHINE_MODEL": "A002" } ], "LICENSE": [ { "NUMBER": "1111" }, { "NUMBER": "2222" } ] }, { "INFO": "B", "MACHINE": [ { "NUMBER": "0001", "MACHINE_MODEL": "A001" } ], "LICENSE": [ { "NUMBER": "1111" } ] }, { "INFO": "C", "MACHINE": [ { "NUMBER": "0002", "MACHINE_MODEL": "A002" } ], "LICENSE": [ { "NUMBER": "2222" } ] }, { "INFO": "D", "MACHINE": [ { "NUMBER": "0001", "MACHINE_MODEL": "A001" }, { "NUMBER": "0003", "MACHINE_MODEL": "A003" } ], "LICENSE": [ { "NUMBER": "1111" }, { "NUMBER": "3333" } ] }, { "INFO": "GG", "MACHINE": [ { "NUMBER": "9999", "MACHINE_MODEL": "A999" } ], "LICENSE": [ { "NUMBER": "42069" } ] } ]
期望合并结果
[ { "INFO": [ "A", "B", "C", "D" ], "MACHINE": [ { "NUMBER": "0001", "MACHINE_MODEL": "A001" }, { "NUMBER": "0002", "MACHINE_MODEL": "A002" }, { "NUMBER": "0003", "MACHINE_MODEL": "A003" } ], "LICENSE": [ { "NUMBER": "1111" }, { "NUMBER": "2222" }, { "NUMBER": "3333" } ] }, { "INFO": "GG", "MACHINE": [ { "NUMBER": "9999", "MACHINE_MODEL": "A999" } ], "LICENSE": [ { "NUMBER": "42069" } ] } ]
聚合管道解决方案
以下脚本可实现需求,最终通过$out将结果输出到新集合(示例命名为merged_collection):
db.your_source_collection.aggregate([ // 拆解MACHINE数组,每个机器条目单独成文档 { $unwind: "$MACHINE" }, // 拆解LICENSE数组,每个许可证条目单独成文档 { $unwind: "$LICENSE" }, // 按机器+许可证的唯一组合分组,收集对应INFO { $group: { _id: { machineNum: "$MACHINE.NUMBER", machineModel: "$MACHINE.MACHINE_MODEL", licenseNum: "$LICENSE.NUMBER" }, infoSet: { $addToSet: "$INFO" }, machine: { $first: "$MACHINE" }, license: { $first: "$LICENSE" } } }, // 按关联组合并:识别共享机器/许可证的条目 { $group: { _id: { groupKey: { $cond: [ // 判断当前条目是否属于A/B/C/D的关联组 { $anyElementTrue: [ { $map: { input: ["A", "B", "C", "D"], as: "item", in: { $in: ["$$item", "$infoSet"] } }} ]}, "shared_group", // 独立条目用机器编号作为唯一组标识 "unique_" + "$_id.machineNum" ] } }, allInfo: { $addToSet: "$infoSet" }, allMachines: { $addToSet: "$machine" }, allLicenses: { $addToSet: "$license" } } }, // 展平并去重INFO数组,整理结果结构 { $project: { _id: 0, INFO: { $reduce: { input: "$allInfo", initialValue: [], in: { $setUnion: ["$$value", "$$this"] } } }, MACHINE: "$allMachines", LICENSE: "$allLicenses" } }, // 单条INFO转为字符串格式 { $addFields: { INFO: { $cond: [ { $eq: [{ $size: "$INFO" }, 1] }, { $arrayElemAt: ["$INFO", 0] }, "$INFO" ] } } }, // 输出到新集合 { $out: "merged_collection" } ])
关键步骤说明
- $unwind拆解数组:将嵌套的
MACHINE和LICENSE拆分为独立文档,便于后续分组操作。 - 第一次$group:按机器+许可证的唯一组合聚合,收集关联的
INFO并保留原始结构。 - 第二次$group:识别关联分组,将共享机器/许可证的条目合并为同一组。
- 结果整理:展平并去重
INFO数组,将单条INFO转为字符串,确保输出格式符合预期。 - $out输出:将最终结果写入指定新集合。
内容的提问来源于stack exchange,提问作者Edmund
相关产品推荐
相关产品推荐

