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

Mongo JPA能否实现多分组聚合:按分类统计行数与最新日期金额?

解决方案:单聚合管道实现需求

你不需要多步操作,通过MongoDB的单聚合管道就能完成这个需求,对应的Mongo JPA(Spring Data MongoDB)也能直接实现。

1. MongoDB Shell 原生聚合命令

先看底层聚合逻辑,理解实现步骤:

db.collection.aggregate([
  // 按category分组,统计数量并收集每个分组的日期、金额数据
  {
    $group: {
      _id: "$category",
      count: { $sum: 1 },
      docs: { $push: { date: "$date", amount: "$amount" } }
    }
  },
  // 计算每个分组的最大日期
  {
    $addFields: {
      maxDate: { $max: "$docs.date" }
    }
  },
  // 过滤出最大日期对应的金额
  {
    $addFields: {
      last_amount: {
        $arrayElemAt: [
          { $map: {
              input: { $filter: {
                  input: "$docs",
                  cond: { $eq: ["$$this.date", "$maxDate"] }
                }
              },
              as: "item",
              in: "$$item.amount"
            }
          }, 0
        ]
      }
    }
  },
  // 整理输出字段,重命名_id为category
  {
    $project: {
      _id: 0,
      category: "$_id",
      count: 1,
      last_amount: 1
    }
  }
])

执行后会直接返回你预期的结果结构。

2. Mongo JPA(Spring Data MongoDB)代码实现

实体类定义(假设你的数据实体为ProductRecord)

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import java.time.LocalDate;

@Document(collection = "your_collection_name")
public class ProductRecord {
    @Id
    private String id;
    private String category;
    private LocalDate date;
    private Integer amount;

    // Getters & Setters
}

聚合操作实现

import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.*;
import java.util.List;

// 注入MongoTemplate
private final MongoTemplate mongoTemplate;

public List<CategoryStats> queryCategoryStats() {
    // 1. 分组操作:按category分组,统计数量、收集日期金额数据
    GroupOperation groupByCategory = Aggregation.group("category")
            .count().as("count")
            .push(Aggregation.fields().and("date").and("amount")).as("docs");

    // 2. 添加分组内的最大日期字段
    AddFieldsOperation addMaxDate = Aggregation.addFields()
            .field("maxDate")
            .withValue(Aggregation.max("docs.date"))
            .build();

    // 3. 筛选并提取最大日期对应的金额
    AddFieldsOperation addLastAmount = Aggregation.addFields()
            .field("last_amount")
            .withValue(ArrayOperators.ArrayElemAt.arrayOf(
                    ArrayOperators.Map.itemsOf(
                            Aggregation.filter("docs")
                                    .as("item")
                                    .by(Aggregation.compareValueOf("item.date").to("maxDate").equalToValue())
                    ).as("item").andApply("item.amount")
            ).elementAt(0))
            .build();

    // 4. 投影整理输出字段
    ProjectionOperation projectFields = Aggregation.project()
            .andExclude("_id")
            .and("_id").as("category")
            .andInclude("count", "last_amount");

    // 构建并执行聚合管道
    Aggregation aggregation = Aggregation.newAggregation(
            groupByCategory,
            addMaxDate,
            addLastAmount,
            projectFields
    );

    AggregationResults<CategoryStats> results = mongoTemplate.aggregate(
            aggregation,
            "your_collection_name", // 替换为你的集合名称
            CategoryStats.class
    );

    return results.getMappedResults();
}

// 结果映射类
public static class CategoryStats {
    private String category;
    private Integer count;
    private Integer last_amount;

    // Getters & Setters
}

关键逻辑说明

  • 分组阶段用$push保存每个分组内的日期和金额关联数据,避免丢失对应关系;
  • 通过$max计算分组内的最大日期;
  • 用$filter筛选出数组中匹配最大日期的元素,再通过$map和$arrayElemAt提取对应的金额值;
  • 最后通过投影操作整理输出字段,得到目标结构。

整个过程是单管道一次性完成,无需拆分多步查询。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 02:00:32