MongoDB $unionWith去重:优先保留customerMaster文档的$group写法
解决MongoDB $unionWith后去重并优先保留customerMaster文档的问题
要实现合并两个集合后按userName去重,且优先保留customerMaster中的文档,核心思路是给两个集合的文档添加来源标识/优先级,再通过$group阶段根据优先级筛选目标文档。以下是两种可行的实现方案:
方案一:通过排序取优先文档
先给每个集合的文档标记来源,合并后将同一userName的文档存入数组,再按来源优先级排序,取排序后的第一个文档(即customerMaster的文档):
[ { '$match': { 'userName': { '$in': userList } } }, // 给userMaster的文档添加来源标记 { '$addFields': { 'source': 'userMaster' } }, { '$unionWith': { 'coll': 'customerMaster', 'pipeline': [ { '$match': { 'userName': { '$in': userList } } }, // 给customerMaster的文档添加来源标记 { '$addFields': { 'source': 'customerMaster' } } ] } }, // 按userName分组,收集同一用户的所有文档 { '$group': { '_id': '$userName', 'docs': { '$push': '$$ROOT' } } }, // 对文档数组按source排序,customerMaster排首位 { '$addFields': { 'sortedDocs': { '$sortArray': { 'input': '$docs', // 字符串排序中"customerMaster"比"userMaster"靠后,降序后优先取前者 'sortBy': { 'source': -1 } } } } }, // 替换根文档为排序后的第一个文档 { '$replaceRoot': { 'newRoot': { '$first': '$sortedDocs' } } }, // 可选:移除source标记字段 { '$project': { 'source': 0 } } ]
方案二:通过优先级数字筛选
给两个集合的文档设置不同的优先级数值(customerMaster优先级更高),利用$max直接筛选出优先级最高的文档,实现更简洁:
[ { '$match': { 'userName': { '$in': userList } } }, // userMaster优先级设为1(低) { '$addFields': { 'sourcePriority': 1 } }, { '$unionWith': { 'coll': 'customerMaster', 'pipeline': [ { '$match': { 'userName': { '$in': userList } } }, // customerMaster优先级设为2(高) { '$addFields': { 'sourcePriority': 2 } } ] } }, // 按userName分组,取优先级最高的文档 { '$group': { '_id': '$userName', 'finalDoc': { '$max': { 'priority': '$sourcePriority', 'doc': '$$ROOT' } } } }, // 替换根文档为筛选后的目标文档 { '$replaceRoot': { 'newRoot': '$finalDoc.doc' } }, // 可选:移除优先级字段 { '$project': { 'sourcePriority': 0 } } ]
关键说明
- 两种方案的核心都是标记文档来源,确保能区分
userMaster和customerMaster的文档; - 优先保留
customerMaster文档的逻辑,本质是在分组时选择该集合的文档作为最终结果,从而保留address等专属字段。
内容的提问来源于stack exchange,提问作者Vitthal Kulkarni
相关产品推荐
相关产品推荐

