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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 07:01:00