如何将MongoDB按年分组统计的聚合查询转为Java Aggregation实现
MongoDB聚合查询转Spring Data MongoDB Java实现
需求说明
按createdAt字段的年份与status字段组合分组,统计每组对应的文档数量,对应MongoDB原生聚合查询包含$group、$replaceWith、$unset三个阶段。
原生MongoDB查询
db.collection.aggregate([ { $group: { _id: { year: { $year: "$createdAt" }, status: "$status" }, count: { $sum: 1 } } }, { $replaceWith: { $mergeObjects: [ "$_id", "$$ROOT" ] } }, { $unset: "_id" } ])
问题分析
你尝试的Java代码存在以下问题:
- 分组条件错误:未按
createdAt的年份+status组合分组,直接使用了createdAt原始字段 - 统计字段命名不匹配:原生查询用
count,代码中用了yearly - 缺失
$replaceWith和$unset对应的聚合阶段
正确Java实现
1. 定义结果接收实体类
创建与聚合结果字段匹配的实体类,用于映射查询结果:
public class YearlyStatusCount { private Integer year; private String status; private Long count; // 无参构造函数(Spring Data MongoDB要求) public YearlyStatusCount() {} // 全参构造函数 public YearlyStatusCount(Integer year, String status, Long count) { this.year = year; this.status = status; this.count = count; } // 自行补充getter、setter方法 public Integer getYear() { return year; } public void setYear(Integer year) { this.year = year; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } public Long getCount() { return count; } public void setCount(Long count) { this.count = count; } }
2. 构建聚合查询代码
import org.springframework.data.mongodb.core.aggregation.*; import org.springframework.data.mongodb.core.MongoOperations; import java.util.Arrays; import java.util.List; import org.bson.Document; // 1. 构建$group阶段:按年份和status分组,统计文档数 GroupOperation groupOp = Aggregation.group( Fields.from( // 用$year表达式提取createdAt的年份作为分组键 Fields.field("year", AggregationExpression.from(ctx -> new Document("$year", "$createdAt") )), // 按status字段分组 Fields.field("status", "$status") ) ).sum(1).as("count"); // 对应$sum:1,统计数量并命名为count // 2. 构建$replaceWith阶段:合并_id和当前文档内容 ReplaceWithOperation replaceWithOp = Aggregation.replaceWith( AggregationExpression.from(ctx -> new Document("$mergeObjects", Arrays.asList("$_id", "$$ROOT")) ) ); // 3. 构建$unset阶段:移除_id字段 UnsetOperation unsetOp = Aggregation.unset("_id"); // 组合所有聚合阶段 Aggregation aggregation = Aggregation.newAggregation(groupOp, replaceWithOp, unsetOp); // 执行聚合查询,映射到实体类 AggregationResults<YearlyStatusCount> results = mongoOperations.aggregate( aggregation, "collection", // 替换为你的集合名称 YearlyStatusCount.class ); // 获取最终结果列表 List<YearlyStatusCount> countList = results.getMappedResults();
关键说明
GroupOperation:通过AggregationExpression实现MongoDB的$year表达式,确保按年份而非原始日期字段分组ReplaceWithOperation:对应原生的$replaceWith,用$mergeObjects将分组键(_id内的year和status)合并到根文档UnsetOperation:移除不需要的_id字段,使结果结构更简洁
内容的提问来源于stack exchange,提问作者YourDaddyProgrammer
相关产品推荐
相关产品推荐

