Spring MongoDB计算对象数组总和并映射DTO的问题
问题描述
集合结构
{ _id:1, meterId:1, Date: 2021-03-01, consumption:[ { value:10}, {value:7} ] }
期望返回结果
{ meterId:1, Date: 2021-03-01, consumption:[ { value:10}, {value:7} ], total:17 }
自定义DTO
public class ConsumptionDTO { @Field("Date") // 映射文档中的大写Date字段 protected Date date; protected String meterId; protected List<ConsumptionPoint> consumption; protected double total; // 新增字段 // 构造方法、getter和setter }
尝试的代码(存在问题)
List<ConsumptionDTO> consumptions =new ArrayList<>(); AggregationOperation filter = Aggregation.match(Criteria.where("meterId").in(meterIds).and("date").gte(startDate).lte(endDate)); AggregationOperation sum = Aggregation.group().sum("consumption.value").as("total"); Aggregation aggregation = Aggregation.newAggregation(filter, sum); consumptions = mongoTemplate.aggregate(aggregation,collectionName,ConsumptionDTO.class).getMappedResults();
解决方案
问题分析
- 字段大小写不匹配:MongoDB字段名区分大小写,文档中日期字段为
Date(大写D),但代码中使用了date(小写d),导致match条件无法匹配到任何文档,聚合结果为空。 - 错误使用group操作:
Aggregation.group()不带分组键会将所有匹配文档合并为一个分组,且分组阶段会丢弃原文档的meterId、Date、consumption等字段,无法映射到ConsumptionDTO的完整结构。
修正后的实现
我们需要保留原文档所有字段,同时为每个文档计算consumption数组的总和,使用addFields操作新增total字段而非group:
List<ConsumptionDTO> consumptions = new ArrayList<>(); // 1. 修正字段大小写,匹配文档中的Date字段 AggregationOperation filter = Aggregation.match( Criteria.where("meterId").in(meterIds) .and("Date").gte(startDate).lte(endDate) ); // 2. 用addFields为每个文档新增total字段,计算consumption.value的总和 AggregationOperation addTotalField = Aggregation.addFields() .addFieldWithValue("total", Aggregation.sum("consumption.value")) .build(); // 3. 组装聚合操作 Aggregation aggregation = Aggregation.newAggregation(filter, addTotalField); // 4. 执行聚合并映射到DTO consumptions = mongoTemplate.aggregate(aggregation, collectionName, ConsumptionDTO.class).getMappedResults();
补充说明
- 必须给
ConsumptionDTO的date字段添加@Field("Date")注解,否则Spring Data MongoDB无法正确映射文档中的大写Date字段到DTO的小写date属性。 addFields操作会保留原文档的所有字段,同时新增指定的total字段,完全符合期望的返回结构。
内容的提问来源于stack exchange,提问作者Karim Halayqa
相关产品推荐
相关产品推荐

