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

单分组双聚合统计:MongoDB查询转Spring Data实现求助

嘿,我来帮你把这段MongoDB聚合查询转换成Spring Data MongoDB的完整实现,给你两种常用方案参考,都是能直接落地的!

方案一:使用Spring Data Aggregation API(类型安全)

这种方式用Spring提供的聚合API构建查询,不用写原生MongoDB字符串,类型更安全,也更易维护。

第一步:定义Student实体类

先把数据库的student集合映射成Java实体,注意字段和数据库的对应关系:

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;

@Document(collection = "student")
public class Student {
    @Id
    private String id;
    
    @Field("student_name") // 对应数据库的student_name字段
    private String studentName;
    
    @Field("student_age") // 对应数据库的student_age字段
    private Integer studentAge;

    // 别忘了加无参构造器、全参构造器,以及getter/setter方法
}

第二步:定义聚合结果接收类

聚合查询返回的是分组统计数据,需要一个类来映射结果:

public class StudentAggStats {
    private String _id; // 对应分组的student_name
    private long count; // 每个姓名对应的学生数量
    private int sum1; // 每个姓名对应的年龄总和

    // 构造器、getter/setter方法
}

第三步:编写聚合查询逻辑

在Service层用MongoTemplate执行聚合管道:

import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.GroupOperation;
import org.springframework.data.mongodb.core.aggregation.MatchOperation;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class StudentStatsService {

    private final MongoTemplate mongoTemplate;

    // 构造注入MongoTemplate(Spring Boot会自动配置)
    public StudentStatsService(MongoTemplate mongoTemplate) {
        this.mongoTemplate = mongoTemplate;
    }

    public List<StudentAggStats> getNon15AgeStudentStats() {
        // 1. 构建$match阶段:过滤年龄不等于15的学生
        MatchOperation matchStage = Aggregation.match(Criteria.where("student_age").ne(15));

        // 2. 构建$group阶段:按student_name分组,统计数量和年龄总和
        GroupOperation groupStage = Aggregation.group("$student_name")
                .count().as("count") // 对应原生的count: {$sum:1}
                .sum("student_age").as("sum1"); // 对应原生的sum1: {$sum:"$student_age"}

        // 3. 组装完整的聚合管道
        Aggregation aggregation = Aggregation.newAggregation(matchStage, groupStage);

        // 4. 执行聚合查询,映射到结果类
        AggregationResults<StudentAggStats> results = mongoTemplate.aggregate(
                aggregation, 
                "student", // 目标集合名
                StudentAggStats.class
        );

        return results.getMappedResults();
    }
}
方案二:使用自定义Repository + @Aggregation注解

如果更习惯写原生MongoDB聚合语法,可以直接在Repository接口里用@Aggregation注解,简单直接:

第一步:定义StudentRepository接口

继承MongoRepository,并添加自定义聚合方法:

import org.springframework.data.mongodb.repository.Aggregation;
import org.springframework.data.mongodb.repository.MongoRepository;

import java.util.List;

public interface StudentRepository extends MongoRepository<Student, String> {

    // 直接写原生MongoDB聚合管道
    @Aggregation(pipeline = {
            "{ '$match': { 'student_age': { '$ne': 15 } } }",
            "{ '$group': { '_id': '$student_name', 'count': { '$sum': 1 }, 'sum1': { '$sum': '$student_age' } } }"
    })
    List<StudentAggStats> findNon15AgeStudentStats();
}

第二步:使用Repository

在Service或者Controller里直接注入StudentRepository调用方法即可:

import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class StudentStatsService {

    private final StudentRepository studentRepository;

    public StudentStatsService(StudentRepository studentRepository) {
        this.studentRepository = studentRepository;
    }

    public List<StudentAggStats> getNon15AgeStudentStats() {
        return studentRepository.findNon15AgeStudentStats();
    }
}
注意事项
  • 确保实体类的@Field注解和数据库字段完全匹配,避免Spring自动驼峰转换导致字段不匹配的问题
  • 聚合结果类的字段名要和聚合管道里定义的别名(比如count、sum1)完全一致,_id对应分组的字段值
  • 如果你的需求是统计所有非15岁学生的总数量和总年龄(而不是按姓名分组),只需要把$group的_id改成null即可,对应到Spring API里就是Aggregation.group(null)

内容的提问来源于stack exchange,提问作者Sam

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 10:13:41