使用MongoDB聚合$filter统计两个数组匹配元素数量的问题
MongoDB聚合统计数组元素匹配数量问题解决
问题说明
需要统计用户输入数组与后端存储的数组之间的匹配元素个数:
- 用户输入
[1,2,3,4],与后端数组[1,2,3,4]比对,期望返回匹配数4 - 用户输入
[1,2,3,5],与后端数组[1,2,3,4]比对,期望返回匹配数3
但现有聚合查询返回结果错误,完全匹配时仅返回1,无法实现需求。
现有查询的问题
原查询使用$filter遍历entries数组,判断整个numbers数组是否与输入数组完全相等,最终统计的是匹配的entries条目数,而非数组内元素的匹配数量。这就是为什么完全匹配时返回1——仅表示有一个entries元素的numbers数组和输入数组完全一致,而非4个元素匹配。
原查询代码:
db.collection.aggregate({ $match: { "entries.numbers": { $in: [1,2,3,4] } } }, { "$addFields": { "matchingCount": { $size: { $filter: { input: "$entries", as: "e", cond: { $eq: ["$$e.numbers", [1,2,3,4]] } } } } } })
解决方案
使用$setIntersection获取两个数组的交集,再用$size获取交集的长度,即可得到元素级别的匹配数量。根据需求不同,有三种实现方式:
方式1:为每个entries元素计算匹配数
如果需要给每个entries对象添加对应的元素匹配数,用$map遍历entries数组,对每个元素的numbers数组计算交集大小:
db.collection.aggregate([ { $match: { "entries.numbers": { $in: [1,2,3,4] } } }, { $addFields: { entriesWithMatch: { $map: { input: "$entries", as: "e", in: { numbers: "$$e.numbers", matchingCount: { $size: { $setIntersection: ["$$e.numbers", [1,2,3,4]] } } } } } } } ])
方式2:计算所有entries元素的总匹配数
如果需要统计整个文档中所有entries的numbers数组与输入数组的总匹配元素数,用$reduce累加每个元素的匹配数:
db.collection.aggregate([ { $match: { "entries.numbers": { $in: [1,2,3,4] } } }, { $addFields: { totalMatchingCount: { $reduce: { input: "$entries", initialValue: 0, in: { $add: [ "$$value", { $size: { $setIntersection: ["$$this.numbers", [1,2,3,4]] } } ] } } } } } ])
方式3:针对单个numbers数组计算匹配数
如果文档中entries仅包含一个numbers数组,可直接提取该数组计算交集:
db.collection.aggregate([ { $match: { "entries.numbers": { $in: [1,2,3,4] } } }, { $addFields: { matchingCount: { $size: { $setIntersection: ["$entries.0.numbers", [1,2,3,4]] } } } } ])
内容的提问来源于stack exchange,提问作者user874737
相关产品推荐
相关产品推荐

