如何查询MongoDB中数组字段存在重复值的记录
解决MongoDB集合中找出包含重复元素数组的记录
嘿,你的思路方向完全正确!其实MongoDB里有个非常适配这个场景的操作符——$setUnion,它能帮你快速完成数组去重,我们只需要对比原数组和去重后数组的长度,就能精准筛选出包含重复元素的记录了。
方案一:直接对比对象数组(最简便)
如果你的重复元素是完全相同的对象(比如示例中两条{ "s": "NL", "k": 2 }),甚至不需要转字符串,直接用$setUnion对boxed.values数组去重即可:
db.collection.aggregate([ // 先过滤掉无boxed.values或数组为空的文档,提升查询效率 { $match: { "boxed.values": { $exists: true, $not: { $size: 0 } } } }, // 添加辅助字段标记是否存在重复 { $addFields: { hasDuplicates: { $ne: [ { $size: "$boxed.values" }, // 原数组长度 { $size: { $setUnion: ["$boxed.values", []] } } // 去重后数组长度 ] } } }, // 筛选出存在重复的记录 { $match: { hasDuplicates: true } }, // 移除辅助字段,返回原文档结构 { $project: { hasDuplicates: 0 } } ])
方案二:转字符串数组去重(适合自定义重复判断场景)
如果你的重复判断逻辑不是完全匹配对象(比如只关心s和k的组合,哪怕对象有其他额外字段),那你的转字符串思路可以结合$setUnion实现:
db.collection.aggregate([ { $match: { "boxed.values": { $exists: true, $not: { $size: 0 } } } }, { $addFields: { hasDuplicates: { $ne: [ { $size: "$boxed.values" }, { $size: { $setUnion: [ // 将每个元素转为`s*k`格式的字符串 { $map: { input: "$boxed.values", in: { $concat: ["$$this.s", "*", { $toString: "$$this.k" }] } } }, [] ] } } ] } } }, { $match: { hasDuplicates: true } }, { $project: { hasDuplicates: 0 } } ])
这里要注意用$toString把数字类型的k转成字符串,不然$concat会因为类型不匹配报错。
方法原理
$setUnion的核心特性是返回无重复元素的数组,不管输入数组里有多少重复项,它都会自动只保留唯一的一份。所以只要原数组长度和去重后的长度不一致,就说明数组里存在重复元素。
边界情况处理
如果集合里有像第三条那样boxed为空或boxed.values不存在的文档,上面的$match阶段会自动过滤掉它们,避免后续计算报错。如果需要保留这些文档并标记为无重复,只需要调整$match和$addFields里的逻辑即可。
内容的提问来源于stack exchange,提问作者DunDar
相关产品推荐
相关产品推荐

