如何在Spring Boot中对MongoDB单字段执行Group By操作
Spring Boot + MongoDB 单字段Group By实现方案
针对你需要按categoryType字段分组展示MongoDB文档的需求,以下是几种在Spring Boot中实现的常用方式:
1. 先定义实体类
首先创建与MongoDB集合对应的实体类,映射文档结构:
import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; @Document(collection = "sports") // 替换为你的集合名称 public class Sports { @Id private String id; private String categoryType; private String description; // 无参构造、全参构造 public Sports() {} public Sports(String categoryType, String description) { this.categoryType = categoryType; this.description = description; } // getter、setter方法(自行补充完整) public String getId() { return id; } public void setId(String id) { this.id = id; } public String getCategoryType() { return categoryType; } public void setCategoryType(String categoryType) { this.categoryType = categoryType; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } }
2. 使用MongoTemplate实现分组(灵活度最高)
MongoTemplate是Spring Data MongoDB提供的核心操作类,适合复杂聚合场景,支持分组后获取完整文档或统计数量。
场景1:分组后获取每个分类下的所有文档
先定义分组结果的DTO,用于接收聚合返回的数据:
public static class CategoryGroupResult { private String categoryType; private List<Sports> documents; // getter、setter方法 public String getCategoryType() { return categoryType; } public void setCategoryType(String categoryType) { this.categoryType = categoryType; } public List<Sports> getDocuments() { return documents; } public void setDocuments(List<Sports> documents) { this.documents = documents; } }
然后在Service中编写聚合逻辑:
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.ProjectionOperation; import org.springframework.stereotype.Service; import java.util.List; @Service public class SportsService { private final MongoTemplate mongoTemplate; // 构造注入MongoTemplate public SportsService(MongoTemplate mongoTemplate) { this.mongoTemplate = mongoTemplate; } // 按categoryType分组,返回每个分类下的所有文档 public List<CategoryGroupResult> groupByCategoryType() { // 1. 分组操作:按categoryType字段分组,将每组的完整文档存入documents数组 GroupOperation groupOp = Aggregation.group("categoryType") .push("$$ROOT").as("documents"); // 2. 投影操作:重命名字段,让返回结果更直观 ProjectionOperation projectionOp = Aggregation.project("documents") .and("_id").as("categoryType"); // 3. 执行聚合查询 Aggregation aggregation = Aggregation.newAggregation(groupOp, projectionOp); AggregationResults<CategoryGroupResult> results = mongoTemplate.aggregate(aggregation, "sports", CategoryGroupResult.class); return results.getMappedResults(); } }
场景2:仅统计每个分类的文档数量
如果只需要统计数量,简化分组逻辑即可:
// 定义统计结果DTO public static class CategoryCountResult { private String categoryType; private int totalCount; // getter、setter方法 public String getCategoryType() { return categoryType; } public void setCategoryType(String categoryType) { this.categoryType = categoryType; } public int getTotalCount() { return totalCount; } public void setTotalCount(int totalCount) { this.totalCount = totalCount; } } // 统计每个分类的文档数量方法 public List<CategoryCountResult> countByCategoryType() { GroupOperation groupOp = Aggregation.group("categoryType") .count().as("totalCount"); ProjectionOperation projectionOp = Aggregation.project("totalCount") .and("_id").as("categoryType"); Aggregation aggregation = Aggregation.newAggregation(groupOp, projectionOp); AggregationResults<CategoryCountResult> results = mongoTemplate.aggregate(aggregation, "sports", CategoryCountResult.class); return results.getMappedResults(); }
3. 使用MongoRepository自定义聚合查询(适合简单场景)
通过@Aggregation注解直接在Repository接口中编写MongoDB聚合管道,代码更简洁:
首先定义Repository接口:
import org.springframework.data.mongodb.repository.Aggregation; import org.springframework.data.mongodb.repository.MongoRepository; import java.util.List; public interface SportsRepository extends MongoRepository<Sports, String> { // 按categoryType分组统计数量 @Aggregation(pipeline = { "{$group: {_id: '$categoryType', totalCount: {$count: {}}}}", "{$project: {categoryType: '$_id', totalCount: 1, _id: 0}}" }) List<CategoryCountResult> countGroupByCategoryType(); }
然后在Service中调用:
@Service public class SportsService { private final SportsRepository sportsRepository; public SportsService(SportsRepository sportsRepository) { this.sportsRepository = sportsRepository; } public List<CategoryCountResult> getCategoryCounts() { return sportsRepository.countGroupByCategoryType(); } }
4. 测试接口(可选)
编写Controller对外提供接口,验证分组效果:
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController public class SportsController { private final SportsService sportsService; public SportsController(SportsService sportsService) { this.sportsService = sportsService; } // 获取分组后的完整文档列表 @GetMapping("/group-category") public List<SportsService.CategoryGroupResult> getGroupedCategories() { return sportsService.groupByCategoryType(); } // 获取分类统计数量 @GetMapping("/category-counts") public List<SportsService.CategoryCountResult> getCategoryCounts() { return sportsService.countByCategoryType(); } }
内容的提问来源于stack exchange,提问作者Milan Bhatt
相关产品推荐
相关产品推荐

