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-
相关产品推荐
相关产品推荐

