如何在MongoDB Spring Data中对多字段进行聚合统计?
MongoDB Spring Data 实现多数组字段内userId的聚合计数
咱们先明确需求:现有订单数据里包含manager和employee两个数组字段,每个数组里存着带userId的对象,需要把这两个字段里的所有userId合并起来统计出现次数,最终输出一个包含统计结果数组的Agg字段。
核心思路(先看MongoDB原生聚合逻辑)
要实现这个需求,聚合管道需要分这几步走:
- 合并数组:把
manager.userId和employee.userId两个数组合并成一个包含所有userId的数组 - 拆分数组:将合并后的数组拆分为单个文档,每个文档对应一个userId
- 分组统计:按userId分组,统计每个userId出现的总次数
- 调整格式:把统计结果整理成指定的键名,最后打包到
Agg数组中
Spring Data MongoDB 代码实现
首先可以定义两个简单的DTO来接收最终结果:
// 单个用户的统计结果 public class UserCount { private String userId; private int total; // 构造器、getter、setter 省略 } // 最终聚合结果 public class AggregationResult { private List<UserCount> Agg; // 构造器、getter、setter 省略 }
然后用Aggregation类构建聚合管道,通过MongoTemplate执行:
@Autowired private MongoTemplate mongoTemplate; public AggregationResult countUserIds() { // 1. 合并manager和employee的userId数组 ProjectionOperation projectAllUserIds = Aggregation.project() .and(Aggregation.concatArrays("manager.userId", "employee.userId")) .as("allUserIds"); // 2. 拆分合并后的数组 UnwindOperation unwindUserIds = Aggregation.unwind("allUserIds"); // 3. 按userId分组统计次数 GroupOperation groupByUserId = Aggregation.group("allUserIds") .count().as("total"); // 4. 调整字段名,匹配期望输出 ProjectionOperation projectFinalFields = Aggregation.project("total") .and("allUserIds").as("userId"); // 5. 将所有统计结果打包到Agg数组中 GroupOperation wrapIntoAggArray = Aggregation.group() .push(Aggregation.fields().and("userId").and("total")).as("Agg"); // 构建聚合管道并执行 Aggregation aggregation = Aggregation.newAggregation( projectAllUserIds, unwindUserIds, groupByUserId, projectFinalFields, wrapIntoAggArray ); AggregationResults<AggregationResult> results = mongoTemplate.aggregate( aggregation, "your-collection-name", // 替换成你的集合名称 AggregationResult.class ); return results.getUniqueMappedResult(); }
代码解释
concatArrays:把两个数组里的userId提取出来合并成一个数组,这样不管是manager还是employee的userId都被放到同一个集合里unwind:把数组拆成单个文档,确保每个userId都能被单独统计group("allUserIds").count():按userId分组,统计每个userId出现的总次数- 最后一步的
group().push(...):把所有统计后的用户对象打包到Agg数组中,完全匹配你期望的输出格式
内容的提问来源于stack exchange,提问作者opax




