MongoDB聚合统计动态字段匹配记录报错Couldn't find PersistentEntity for type java.lang.Object
问题原因
你遇到的MappingException是Spring Data MongoDB的类型映射机制导致的:当你指定聚合的输入实体为UserAttributesEntity时,框架会尝试校验聚合表达式中用到的字段路径,attributes是Map<String, Object>类型,框架无法推断Map内部动态字段的类型,访问attributes.name这类子路径时就会抛出无法找到Object类型持久化实体的错误。同时你代码里还有字段路径写错的问题,实体里存储动态属性的字段叫attributes,不是userAttributes。
可选解决方案
方案1:使用$expr构造原生查询(推荐)
直接在查询阶段使用MongoDB原生表达式完成过滤,不需要额外投影和聚合流程,性能更高,支持索引优化,代码如下:
private Mono<Long> countByDynamicCondition() { // 对应你的查询条件:((attributes.name == 'Name1' && attributes.age >40) OR (attributes.location == 'IN')) Criteria criteria = Criteria.where("$expr").is( Document.parse("{$or:[" + "{$and:[{$eq:['$attributes.name', 'Name1']}, {$gt:['$attributes.age', 40]}]}," + "{$eq:['$attributes.location', 'IN']}" + "]}") ); return mongoTemplate.count(Query.query(criteria), UserAttributesEntity.class); }
如果你的查询条件是动态生成的,直接拼接成对应的MongoDB表达式字符串传入Document.parse即可,比构造Criteria链式调用的成本低很多。
方案2:使用无类型聚合绕开类型校验
如果你需要保留SPEL表达式的写法,可以指定聚合使用无类型上下文,不让框架做实体字段校验:
private Mono<Long> aggregate() { final Aggregation aggregation = Aggregation .newAggregation( Aggregation.project() .andExpression("((attributes.name == 'Name1' && attributes.age > 40) OR (attributes.location == 'IN'))") .as("result"), Aggregation.match(Criteria.where("result").is(true)), Aggregation.group().count().as("count")) // 关闭类型校验,使用无类型上下文 .with(AggregationOptions.builder().skipTypeCheck().build()); // 直接指定集合名,绕开实体类类型校验 return mongoTemplate.aggregate(aggregation, "UserAttributes", Map.class) .map(result -> Long.valueOf(result.get("count").toString())) .next(); }
内容的提问来源于stack exchange,提问作者Siva Reddy Vippala
相关产品推荐
相关产品推荐

