MongoDB聚合查询如何将嵌套二维数组合并为去重一维数组
MongoDB聚合:多数组字段ObjectId合并去重输出一维数组
问题原因
$addToSet针对数组字段做聚合时,会把每个文档的数组整体作为集合元素存入,最终得到二维嵌套数组,且无法自动处理三个字段之间的重复值,因此不符合预期。
正确聚合实现
以下管道兼容原有的$match、$facet、$group逻辑,单查询即可输出去重后的一维ObjectId数组:
db.funds.aggregate([ // 原有匹配阶段保持不变 { $match: { accountId: ObjectId("替换为实际accountId值"), projectId: ObjectId("替换为实际projectId值"), aps: "替换为实际aps匹配值" } }, // 若原有逻辑包含$facet,保持$facet结构不变,在对应分支内追加后续处理即可 // 示例$facet结构参考: // { // $facet: { // idList: [ // // 原有$group阶段 { $group: { _id: null, personalIdRootList: { $addToSet: "$personalIdRoot" }, personalIdFillList: { $addToSet: "$personalIdFill" }, personalIdCapList: { $addToSet: "$personalIdCap" } } }, // // 新增数组打平+合并去重阶段 { $project: { _id: 0, values: { $setUnion: [ // 打平personalIdRoot二维数组 { $reduce: { input: "$personalIdRootList", initialValue: [], in: { $concatArrays: ["$$value", "$$this"] } } }, // 打平personalIdFill二维数组 { $reduce: { input: "$personalIdFillList", initialValue: [], in: { $concatArrays: ["$$value", "$$this"] } } }, // 打平personalIdCap二维数组 { $reduce: { input: "$personalIdCapList", initialValue: [], in: { $concatArrays: ["$$value", "$$this"] } } } ] } } } // ] // // 其他facet统计分支保持原有逻辑不变 // } // } ])
逻辑说明
$reduce搭配$concatArrays:将$addToSet输出的每个二维数组逐层拼接,打平为一维数组$setUnion:合并三个打平后的一维数组,自动过滤所有重复ObjectId(包括同字段内、跨字段的重复值),最终返回无重复的单层一维数组
性能优化方案
如果不需要保留$facet多分支统计,可将数组合并逻辑前置,查询效率更高:
db.funds.aggregate([ { $match: { accountId: ObjectId("替换为实际accountId值"), projectId: ObjectId("替换为实际projectId值"), aps: "替换为实际aps匹配值" } }, // 提前合并三个数组字段,做容错处理 { $project: { allIds: { $concatArrays: [ { $ifNull: ["$personalIdRoot", []] }, { $ifNull: ["$personalIdFill", []] }, { $ifNull: ["$personalIdCap", []] } ] } } }, // 展开数组 { $unwind: "$allIds" }, // 全局去重 { $group: { _id: null, values: { $addToSet: "$allIds" } } }, { $project: { _id: 0 } } ])
容错提示:如果文档中三个数组字段可能存在
null、不存在或非数组类型,必须加$ifNull转空数组,否则$concatArrays会抛出类型错误导致聚合失败。
内容的提问来源于stack exchange,提问作者Rohit tdr
相关产品推荐
相关产品推荐

