单分组双聚合统计: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
相关产品推荐
相关产品推荐

