MongoDB多分组聚合查询及Spring Data实现问题咨询
解决MongoDB分组统计唯一手机号的问题
咱们先明确需求核心:你要统计指定CAMPAIGN_ID下,每个MESSAGE_CONFIG_ID对应的已送达(DELIVRD)的唯一手机号数量,而不是所有送达记录的条数。之前的代码没有对手机号做去重处理,导致同一个手机号被重复统计,所以结果不符合预期。
一、Mongo Shell 正确实现代码
我们需要分两步分组:先对MESSAGE_CONFIG_ID+mobile去重,再按MESSAGE_CONFIG_ID统计去重后的手机号数量:
db.getCollection('GROUP_ID_DELIVERY_STATUS').aggregate([ // 第一步:过滤指定CAMPAIGN_ID的文档 { "$match": {"CAMPAIGN_ID": "5a70252612d91c7b085df083"} }, // 第二步:展开DATA_LIST数组,把每个数组元素变成独立文档 { "$unwind": "$DATA_LIST" }, // 第三步:只保留状态为DELIVRD的送达记录 { "$match": {"DATA_LIST.status": "DELIVRD"} }, // 第四步:按MESSAGE_CONFIG_ID和mobile分组,实现去重(同一个MESSAGE_CONFIG_ID下的同一个手机号只留一条) { "$group": { "_id": { "MESSAGE_CONFIG_ID": "$MESSAGE_CONFIG_ID", "mobile": "$DATA_LIST.mobile" } } }, // 第五步:按MESSAGE_CONFIG_ID分组,统计去重后的手机号数量 { "$group": { "_id": "$_id.MESSAGE_CONFIG_ID", "unique_delivered_mobile_count": { "$sum": 1 } } }, // 可选:重命名字段让结果更直观 { "$project": { "_id": 0, "MESSAGE_CONFIG_ID": "$_id", "unique_delivered_mobile_count": 1 } } ])
代码解释:
- 前三个阶段和你原来的一致:过滤目标活动、展开数组、筛选已送达记录。
- 第四个
$group是关键:通过MESSAGE_CONFIG_ID+mobile作为分组ID,自动去重同一个配置下的重复手机号。 - 第五个
$group统计每个配置下的唯一手机号总数,最后用$project调整输出格式,让结果更易读。
二、Spring Data MongoDB 正确实现代码
对应上面的聚合逻辑,用Spring Data的AggregationAPI实现:
import org.springframework.data.mongodb.core.aggregation.Aggregation; import static org.springframework.data.mongodb.core.aggregation.Aggregation.*; // 构建聚合操作 Aggregation aggregation = newAggregation( // 过滤指定CAMPAIGN_ID match(Criteria.where("CAMPAIGN_ID").is("5a70252612d91c7b085df083")), // 展开DATA_LIST数组 unwind("DATA_LIST"), // 筛选已送达的记录 match(Criteria.where("DATA_LIST.status").is("DELIVRD")), // 第一步分组:按MESSAGE_CONFIG_ID和mobile去重 group("MESSAGE_CONFIG_ID", "DATA_LIST.mobile"), // 第二步分组:按MESSAGE_CONFIG_ID统计数量 group("_id.MESSAGE_CONFIG_ID").count().as("unique_delivered_mobile_count"), // 调整输出格式 project("unique_delivered_mobile_count").and("_id").as("MESSAGE_CONFIG_ID").andExclude("_id") ); // 执行聚合查询(假设你有MongoTemplate实例) // AggregationResults<DeliveryStatsDto> results = mongoTemplate.aggregate(aggregation, "GROUP_ID_DELIVERY_STATUS", DeliveryStatsDto.class);
代码解释:
- 前三个操作和你原来的一致,重点在两次分组:
- 第一次
group("MESSAGE_CONFIG_ID", "DATA_LIST.mobile")实现去重,此时每个分组对应一个唯一的配置+手机号组合。 - 第二次
group("_id.MESSAGE_CONFIG_ID").count().as(...)统计每个配置下的唯一手机号数量。
- 第一次
- 最后用
project调整输出字段,把分组ID转为MESSAGE_CONFIG_ID,并排除默认的_id字段,让结果结构更清晰。
配套结果DTO:
你需要创建一个对应的DTO类来接收返回数据,比如:
public class DeliveryStatsDto { private String MESSAGE_CONFIG_ID; private long unique_delivered_mobile_count; // 构造器、getter、setter方法 }
内容的提问来源于stack exchange,提问作者Muddassir Rahman
相关产品推荐
相关产品推荐

