Spring Boot升级后Mongo Template聚合结果映射失败
Spring Boot 2.4升级后MongoDB聚合查询结果无法映射到DTO的解决思路
问题描述
将Spring Boot版本从2.2.6.RELEASE升级至2.4后,MongoDB聚合查询结果无法映射到StatusSummeryDTO,所有字段均返回null。通过groupResults.getRawResults()可见聚合原始数据包含所需值,但未找到Mongo官方文档中相关的聚合或映射更新说明。尝试更换MongoDB驱动版本、调整Spring Boot小版本均未解决,相同代码在2.2.6.RELEASE版本中可正常运行。
相关代码:
final Aggregation agg = newAggregation(match(Criteria.where("id.cid").is(cId)), group("sId.assignmentId", "status").count().as("total"), sort(Sort.Direction.DESC, "sId.assignmentId", "status")); final AggregationResults<StatusSummeryDTO> groupResults = mongoTemplate.aggregate(agg, Submission.class, StatusSummeryDTO.class); return groupResults.getMappedResults();
核心原因
Spring Boot 2.4对应的Spring Data MongoDB版本(3.1.x及以上)对聚合分组的结果映射逻辑做了调整:
旧版本中,分组时指定的嵌套字段(如sId.assignmentId)会直接作为顶层字段返回用于映射;新版本中,所有分组键会被统一封装到_id嵌套对象中,比如聚合结果的实际结构为:
{ "_id": { "sId.assignmentId": "xxx", "status": "yyy" }, "total": 10 }
而StatusSummeryDTO的字段名还是sId.assignmentId、status,无法和_id下的嵌套键对应,导致映射失败。
解决方案
方案1:给DTO字段添加@Field注解指定映射路径
修改StatusSummeryDTO,通过@Field注解明确指定聚合结果中的实际键名:
public class StatusSummeryDTO { @Field("_id.sId.assignmentId") private String assignmentId; @Field("_id.status") private String status; @Field("total") private Long total; // 省略getter、setter方法 }
方案2:在聚合阶段添加project重命名字段,剥离_id嵌套
调整聚合查询,通过project阶段将_id下的分组键提取为顶层字段,让结果结构和DTO字段直接匹配:
final Aggregation agg = newAggregation( match(Criteria.where("id.cid").is(cId)), group("sId.assignmentId", "status").count().as("total"), // 提取_id下的字段为顶层字段 project("total") .and("_id.sId.assignmentId").as("assignmentId") .and("_id.status").as("status"), sort(Sort.Direction.DESC, "assignmentId", "status") );
修改后聚合返回的结果结构变为:
{ "assignmentId": "xxx", "status": "yyy", "total": 10 }
无需修改DTO即可完成映射。
方案3:检查并调整Mongo映射配置(不推荐)
确认MongoMappingContext未禁用字段自动映射,但该方法可能引入其他兼容性问题,仅作为备选。
内容的提问来源于stack exchange,提问作者Kaveen M.
相关产品推荐
相关产品推荐

