Spring MongoTemplate内嵌对象字段投影及去重优化问题
MongoDB聚合投影嵌套字段到顶层类的问题
问题背景
原始MongoDB文档结构:
{ "sourced": { "reference": "a", "otherField": 1 }, "derived": "Q" }
最终目标:将文档精简为仅包含顶层reference字段的结构,并去除重复数据:
{ "reference": "a" }
现有代码使用两个嵌套类可实现需求,但希望仅用一个包含reference属性的类。尝试Aggregation.project("sourced.reference")时,映射到类的字段返回null;尝试将sourced.reference投影到reference也未成功。
现有可行代码:
@Data private static class ReducedEntity { Sourced sourced; } @Data private static class Sourced { private String reference; } var aggregation = Aggregation.newAggregation( match(new Criteria()), Aggregation.project("sourced") ); AggregationResults<ReducedEntity> results = mongoTemplate.aggregate(aggregation, collectionName, ReducedEntity.class); List<ReducedEntity> mappedResult = results.getMappedResults(); return mappedResult.stream().map(book -> book.sourced.reference).collect(Collectors.toList());
解决方案
核心问题原因
直接用Aggregation.project("sourced.reference")时,MongoDB返回的结果结构是{"sourced.reference": "a"},而非顶层的{"reference": "a"},无法和单个类的reference属性匹配,导致字段为null。必须显式指定投影别名,将嵌套字段映射到顶层字段,同时添加去重逻辑。
实现代码
- 定义单个目标类:
@Data private static class ReducedEntity { private String reference; }
- 正确的聚合管道:
var aggregation = Aggregation.newAggregation( match(new Criteria()), // 保留原有查询条件 // 显式将嵌套的sourced.reference映射为顶层reference字段 Aggregation.project().and("sourced.reference").as("reference"), // 按reference分组实现去重,保留每个值的一条记录 Aggregation.group("reference").first("reference").as("reference"), // 最终投影确保结构纯净,匹配目标类 Aggregation.project("reference") ); AggregationResults<ReducedEntity> results = mongoTemplate.aggregate(aggregation, collectionName, ReducedEntity.class); List<ReducedEntity> mappedResult = results.getMappedResults(); // 如需转换为字符串列表,直接映射即可 List<String> referenceList = mappedResult.stream().map(ReducedEntity::getReference).collect(Collectors.toList());
代码说明
Aggregation.project().and("sourced.reference").as("reference"):强制将嵌套字段重命名为顶层的reference,确保和类属性名一致。Aggregation.group("reference").first("reference").as("reference"):通过分组去重,避免返回重复的reference值。- 最后一次投影是为了过滤分组阶段产生的冗余字段,保证输出结构完全匹配目标类。
内容的提问来源于stack exchange,提问作者Leos Literak
相关产品推荐
相关产品推荐

