You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 14:15:36