Spring-Data-MongoDB中$facet/$addFields/$function返回null解决方法
Spring Data MongoDB使用
$facet+$addFields+$function返回null、自定义字段缺失问题修复 问题根因
出现返回字段全为null、自定义max字段未添加的核心原因有两个:
- 结果映射类型不匹配:
$facet聚合的返回结果最外层是{facet别名: 管道输出文档数组}的结构,不是直接的业务实体列表,原代码直接将结果映射到User.class时,根层级不存在_id、username等业务字段,因此全部映射为null - 实体类字段缺失:原
User实体类未定义自定义计算的max字段,即使聚合管道计算出该字段,也无法完成映射 - 额外逻辑笔误:原Mongo原生语句的匹配条件是
age > 18,最初代码中写为age >= 18,如果需要和原生语句逻辑完全对齐需要调整匹配条件
修复方案
定义和聚合输出结构完全匹配的DTO类完成结果映射,具体实现如下:
1. 调整聚合查询方法
public List<MaxFacet> aggregation1() { List<Object> args = new LinkedList<>(); args.add("$name"); args.add("$scores"); // 定义$function自定义计算逻辑 ScriptOperators.Function maxScoreFunction = Function.function( "function(name, scores) {let max = Math.max(...scores); return `Hello ${name}. Your max score is ${max}.`}") .args(args).lang("js"); // 构建facet管道,对齐原生语句的age>18匹配条件 FacetOperation facetOperation = Aggregation.facet() .and( Aggregation.match(Criteria.where("age").gt(18)), Aggregation.addFields().addFieldWithValue("max", maxScoreFunction).build() ).as("aggregation"); Aggregation agg = Aggregation.newAggregation(facetOperation); // 映射到和facet外层结构匹配的MaxFacet类 return mongoOperations.aggregate(agg, mongoTemplate.getCollectionName(User.class), MaxFacet.class) .getMappedResults(); }
2. 定义facet外层结构映射类
public class MaxFacet { private List<UserOut> aggregation; public List<UserOut> getAggregation() { return aggregation; } public void setAggregation(List<UserOut> aggregation) { this.aggregation = aggregation; } }
3. 定义facet内部文档输出类
@JsonPropertyOrder({"id","username","name","age","scores","max"}) public class UserOut { @JsonProperty(value="id") private String id; private String username; private String name; private Integer age; private String[] role; private Integer[] scores; private String max; // 各字段getter/setter public String getId() { return id; } public void setId(String id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String[] getRole() { return role; } public void setRole(String[] role) { this.role = role; } public Integer[] getScores() { return scores; } public void setScores(Integer[] scores) { this.scores = scores; } public String getMax() { return max; } public void setMax(String max) { this.max = max; } }
修复后返回结果
执行修复后的代码即可得到正确结果,结构示例如下:
[ { "aggregation": [ { "id": "62c5f16b39b3d635ab6bf60d", "username": "james34", "name": "james", "age": 34, "role": ["user", "specialuser"], "scores": [10,9,10], "max": "Hello james. Your max score is 10." }, { "id": "62c5f1b839b3d635ab6bf60e", "username": "elizabeth54", "name": "elizabeth", "age": 54, "role": ["user", "specialuser"], "scores": [10,10,10], "max": "Hello elizabeth. Your max score is 10." } ] } ]
内容的提问来源于stack exchange,提问作者Breathd
相关产品推荐
相关产品推荐

