如何对嵌入式文档使用$regex查询并按渠道统计客户数量
解决MongoDB按符合条件渠道分组统计客户数量的问题
嘿,我来帮你搞定这个MongoDB聚合的问题!先理清楚你的需求:要找出至少拥有一个名称以.xz结尾、且provider属性存在并赋值的渠道的客户,然后按这些合格渠道的名称统计对应的客户数量。
你的现有查询有几个关键问题需要修正:
- 字段名写错了:你用了
notificationChannels.properties.provider,但文档里的字段是channels.properties.provider,这会导致匹配不到正确的数据 - 没处理数组结构:
channels是数组类型,直接用_id: "channels.name"分组,MongoDB会把整个数组当成分组键,而不是单个渠道名称 - 缺少数组拆分和过滤:你需要先把数组拆成单个元素,再筛选出符合条件的渠道,之后才能正确分组统计
正确的聚合查询步骤
我给你写了完整的修正版查询,每一步都加了注释:
db.consumers.aggregate([ // 第一步:先筛选出至少有一个合格渠道的客户,减少后续处理的数据量 { $match: { "channels.name": { $regex: /\.xz$/ }, // 注意转义点号,确保只匹配".xz"结尾的名称 "channels.properties.provider": { $exists: true, $ne: null } // 确保provider存在且有实际值 } }, // 第二步:把channels数组拆分成单个文档,每个文档对应一个渠道 { $unwind: "$channels" }, // 第三步:筛选出单个符合条件的渠道(避免统计数组里的其他不合格渠道) { $match: { "channels.name": { $regex: /\.xz$/ }, "channels.properties.provider": { $exists: true, $ne: null } } }, // 第四步:按渠道名称分组,统计对应的客户数量 { $group: { _id: "$channels.name", count: { $sum: 1 } } }, // 可选:格式化输出字段,让结果更直观(不想改的话可以去掉这一步) { $project: { _id: 0, channelName: "$_id", count: 1 } } ])
关键细节说明
- 正则转义:
\.xz$里的反斜杠必须加,不然.会匹配任意字符,比如abcxz这种不带点的字符串也会被误匹配 - 两次$match的作用:第一次是筛选整个客户文档(只要有一个合格渠道就保留),第二次是筛选拆分后的单个渠道,确保只统计真正符合要求的渠道
- 避免重复统计(可选):如果你的数据里存在同一个客户的
channels数组里有多个相同名称的合格渠道,可以在$unwind之后、第二个$match之后,加上这段代码来去重:
这样每个客户每个渠道只会被统计一次,不会因为数组里有多个重复渠道而多算。{ $group: { _id: { consumerId: "$_id", channelName: "$channels.name" } } }, { $replaceRoot: { newRoot: "$_id" } }
示例输出
运行上面的查询后,你会得到类似这样的结果:
{ "channelName" : "email.xz", "count" : 10 } { "channelName" : "sms.xz", "count" : 5 } { "channelName" : "push.xz", "count" : 7 }
内容的提问来源于stack exchange,提问作者Geralt
相关产品推荐
相关产品推荐

