MongoDB 聚合管道 - 计算符合复杂条件的记录数 -(找不到类型 java.lang.Object 的 PersistentEntity!)
MongoDB Aggregation Pipeline - Count no of records that are matching a complex criteria - (Couldn't find PersistentEntity for type java.lang.Object!)
我有包含动态字段的文档,我需要为给定的复杂查询条件查找匹配记录的计数
示例实体
@Document(collection = "UserAttributes")
public class UserAttributesEntity {
@Id
@Getter
private String id;
@NotNull
@Size(min = 1)
@Getter @Setter
private String userId;
@NotNull
@Getter @Setter
private Map<String, Object> attributes = new HashMap<>();
}
示例数据:
{
"_id" : ObjectId("6164542362affb14f3f2fef6"),
"userId" : "89ee6942-289a-48c9-b0bb-210ea7c06a88",
"attributes" : {
"age" : 61,
"name" : "Name1"
}
},
{
"_id" : ObjectId("6164548045cc4456792d5325"),
"userId" : "538abb29-c09d-422e-97c1-df702dfb5930",
"attributes" : {
"age" : 40,
"name" : "Name2",
"location" : "IN"
}
}
预期查询条件:
"((userAttributes.name == 'Name1' && userAttributes.age > 40) OR (userAttributes.location == 'IN'))
使用 $match 构建如此复杂的标准会实施太多,因此我尝试通过 $project 使用 SPEL evolution,如下所示:
private Mono<Long> aggregate() {
final Aggregation aggregation = Aggregation
.newAggregation(
Aggregation.project("userAttributes.playerLevel", "userAttributes.name")
.andExpression("((userAttributes.name == 'Name1' && userAttributes.age > 40) OR (userAttributes.location == 'IN'))")
.as("result"),
Aggregation.match(Criteria.where("result").is(true)),
Aggregation.group().count().as("count"));
return mongoTemplate.aggregate(aggregation, UserAttributesEntity.class, Map.class)
.map(result -> Long.valueOf(result.get("count").toString()))
.next();
}
然而,上述逻辑因异常而失败:
org.springframework.data.mapping.MappingException: Couldn't find PersistentEntity for type java.lang.Object!
at org.springframework.data.mapping.context.MappingContext.getRequiredPersistentEntity(MappingContext.java:119)
at org.springframework.data.mapping.context.PersistentPropertyPathFactory.getPair(PersistentPropertyPathFactory.java:226)
at org.springframework.data.mapping.context.PersistentPropertyPathFactory.createPersistentPropertyPath(PersistentPropertyPathFactory.java:199)
at org.springframework.data.mapping.context.PersistentPropertyPathFactory.lambda$getPersistentPropertyPath(PersistentPropertyPathFactory.java:172)
at java.base/java.util.concurrent.ConcurrentMap.computeIfAbsent(ConcurrentMap.java:330)
at org.springframework.data.mapping.context.PersistentPropertyPathFactory.getPersistentPropertyPath(PersistentPropertyPathFactory.java:171)
at org.springframework.data.mapping.context.PersistentPropertyPathFactory.from(PersistentPropertyPathFactory.java:71)
at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentPropertyPath(AbstractMappingContext.java:295)
at org.springframework.data.mongodb.core.aggregation.TypeBasedAggregationOperationContext.getReferenceFor(TypeBasedAggregationOperationContext.java:163)
at org.springframework.data.mongodb.core.aggregation.TypeBasedAggregationOperationContext.getReference(TypeBasedAggregationOperationContext.java:107)
at org.springframework.data.mongodb.core.aggregation.AggregationExpressionTransformer$AggregationExpressionTransformationContext.getFieldReference(AggregationExpressionTransformer.java:82)
at org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer$CompoundExpressionNodeConversion.convert(SpelExpressionTransformer.java:541)
at org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.transform(SpelExpressionTransformer.java:113)
at org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.transform(SpelExpressionTransformer.java:58)
at org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer$ExpressionNodeConversion.transform(SpelExpressionTransformer.java:215)
at org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer$ExpressionNodeConversion.transform(SpelExpressionTransformer.java:205)
at org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer$OperatorNodeConversion.convert(SpelExpressionTransformer.java:257)
at org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.transform(SpelExpressionTransformer.java:113)
at org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.transform(SpelExpressionTransformer.java:58)
at org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer$ExpressionNodeConversion.transform(SpelExpressionTransformer.java:215)
at org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer$ExpressionNodeConversion.transform(SpelExpressionTransformer.java:205)
at org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer$OperatorNodeConversion.convert(SpelExpressionTransformer.java:251)
at org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.transform(SpelExpressionTransformer.java:113)
at org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.transform(SpelExpressionTransformer.java:105)
at org.springframework.data.mongodb.core.aggregation.ProjectionOperation$ExpressionProjectionOperationBuilder$ExpressionProjection.toMongoExpression(ProjectionOperation.java:438)
at org.springframework.data.mongodb.core.aggregation.ProjectionOperation$ExpressionProjectionOperationBuilder$ExpressionProjection.toDocument(ProjectionOperation.java:433)
at org.springframework.data.mongodb.core.aggregation.ProjectionOperation.toDocument(ProjectionOperation.java:261)
at org.springframework.data.mongodb.core.aggregation.AggregationOperation.toPipelineStages(AggregationOperation.java:55)
at org.springframework.data.mongodb.core.aggregation.AggregationOperationRenderer.toDocument(AggregationOperationRenderer.java:56)
at org.springframework.data.mongodb.core.aggregation.AggregationPipeline.toDocuments(AggregationPipeline.java:81)
at org.springframework.data.mongodb.core.aggregation.Aggregation.toPipeline(Aggregation.java:705)
at org.springframework.data.mongodb.core.AggregationUtil.createPipeline(AggregationUtil.java:105)
at org.springframework.data.mongodb.core.ReactiveMongoTemplate.aggregate(ReactiveMongoTemplate.java:1001)
at org.springframework.data.mongodb.core.ReactiveMongoTemplate.aggregate(ReactiveMongoTemplate.java:970)
我尝试进一步挖掘,它似乎在尝试将项目中使用的字段映射到适当的实体对象时失败了,在这种情况下,这里的投影字段实际上是 Map 对象并且无法识别匹配的实体(当然地图在 UserAttributesEntity 中)-除了上述方法之外,还有更好的方法来解决我的问题吗?
使用原始聚合解决了问题:
return mongoTemplate.aggregate(aggregation, mongoTemplate.getCollectionName(UserAttributesEntity.class), Map.class)
.map(result -> Long.valueOf(result.get("count").toString()))
.next()
我有包含动态字段的文档,我需要为给定的复杂查询条件查找匹配记录的计数
示例实体
@Document(collection = "UserAttributes")
public class UserAttributesEntity {
@Id
@Getter
private String id;
@NotNull
@Size(min = 1)
@Getter @Setter
private String userId;
@NotNull
@Getter @Setter
private Map<String, Object> attributes = new HashMap<>();
}
示例数据:
{
"_id" : ObjectId("6164542362affb14f3f2fef6"),
"userId" : "89ee6942-289a-48c9-b0bb-210ea7c06a88",
"attributes" : {
"age" : 61,
"name" : "Name1"
}
},
{
"_id" : ObjectId("6164548045cc4456792d5325"),
"userId" : "538abb29-c09d-422e-97c1-df702dfb5930",
"attributes" : {
"age" : 40,
"name" : "Name2",
"location" : "IN"
}
}
预期查询条件:
"((userAttributes.name == 'Name1' && userAttributes.age > 40) OR (userAttributes.location == 'IN'))
使用 $match 构建如此复杂的标准会实施太多,因此我尝试通过 $project 使用 SPEL evolution,如下所示:
private Mono<Long> aggregate() {
final Aggregation aggregation = Aggregation
.newAggregation(
Aggregation.project("userAttributes.playerLevel", "userAttributes.name")
.andExpression("((userAttributes.name == 'Name1' && userAttributes.age > 40) OR (userAttributes.location == 'IN'))")
.as("result"),
Aggregation.match(Criteria.where("result").is(true)),
Aggregation.group().count().as("count"));
return mongoTemplate.aggregate(aggregation, UserAttributesEntity.class, Map.class)
.map(result -> Long.valueOf(result.get("count").toString()))
.next();
}
然而,上述逻辑因异常而失败:
org.springframework.data.mapping.MappingException: Couldn't find PersistentEntity for type java.lang.Object!
at org.springframework.data.mapping.context.MappingContext.getRequiredPersistentEntity(MappingContext.java:119)
at org.springframework.data.mapping.context.PersistentPropertyPathFactory.getPair(PersistentPropertyPathFactory.java:226)
at org.springframework.data.mapping.context.PersistentPropertyPathFactory.createPersistentPropertyPath(PersistentPropertyPathFactory.java:199)
at org.springframework.data.mapping.context.PersistentPropertyPathFactory.lambda$getPersistentPropertyPath(PersistentPropertyPathFactory.java:172)
at java.base/java.util.concurrent.ConcurrentMap.computeIfAbsent(ConcurrentMap.java:330)
at org.springframework.data.mapping.context.PersistentPropertyPathFactory.getPersistentPropertyPath(PersistentPropertyPathFactory.java:171)
at org.springframework.data.mapping.context.PersistentPropertyPathFactory.from(PersistentPropertyPathFactory.java:71)
at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentPropertyPath(AbstractMappingContext.java:295)
at org.springframework.data.mongodb.core.aggregation.TypeBasedAggregationOperationContext.getReferenceFor(TypeBasedAggregationOperationContext.java:163)
at org.springframework.data.mongodb.core.aggregation.TypeBasedAggregationOperationContext.getReference(TypeBasedAggregationOperationContext.java:107)
at org.springframework.data.mongodb.core.aggregation.AggregationExpressionTransformer$AggregationExpressionTransformationContext.getFieldReference(AggregationExpressionTransformer.java:82)
at org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer$CompoundExpressionNodeConversion.convert(SpelExpressionTransformer.java:541)
at org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.transform(SpelExpressionTransformer.java:113)
at org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.transform(SpelExpressionTransformer.java:58)
at org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer$ExpressionNodeConversion.transform(SpelExpressionTransformer.java:215)
at org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer$ExpressionNodeConversion.transform(SpelExpressionTransformer.java:205)
at org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer$OperatorNodeConversion.convert(SpelExpressionTransformer.java:257)
at org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.transform(SpelExpressionTransformer.java:113)
at org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.transform(SpelExpressionTransformer.java:58)
at org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer$ExpressionNodeConversion.transform(SpelExpressionTransformer.java:215)
at org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer$ExpressionNodeConversion.transform(SpelExpressionTransformer.java:205)
at org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer$OperatorNodeConversion.convert(SpelExpressionTransformer.java:251)
at org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.transform(SpelExpressionTransformer.java:113)
at org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.transform(SpelExpressionTransformer.java:105)
at org.springframework.data.mongodb.core.aggregation.ProjectionOperation$ExpressionProjectionOperationBuilder$ExpressionProjection.toMongoExpression(ProjectionOperation.java:438)
at org.springframework.data.mongodb.core.aggregation.ProjectionOperation$ExpressionProjectionOperationBuilder$ExpressionProjection.toDocument(ProjectionOperation.java:433)
at org.springframework.data.mongodb.core.aggregation.ProjectionOperation.toDocument(ProjectionOperation.java:261)
at org.springframework.data.mongodb.core.aggregation.AggregationOperation.toPipelineStages(AggregationOperation.java:55)
at org.springframework.data.mongodb.core.aggregation.AggregationOperationRenderer.toDocument(AggregationOperationRenderer.java:56)
at org.springframework.data.mongodb.core.aggregation.AggregationPipeline.toDocuments(AggregationPipeline.java:81)
at org.springframework.data.mongodb.core.aggregation.Aggregation.toPipeline(Aggregation.java:705)
at org.springframework.data.mongodb.core.AggregationUtil.createPipeline(AggregationUtil.java:105)
at org.springframework.data.mongodb.core.ReactiveMongoTemplate.aggregate(ReactiveMongoTemplate.java:1001)
at org.springframework.data.mongodb.core.ReactiveMongoTemplate.aggregate(ReactiveMongoTemplate.java:970)
我尝试进一步挖掘,它似乎在尝试将项目中使用的字段映射到适当的实体对象时失败了,在这种情况下,这里的投影字段实际上是 Map 对象并且无法识别匹配的实体(当然地图在 UserAttributesEntity 中)-除了上述方法之外,还有更好的方法来解决我的问题吗?
使用原始聚合解决了问题:
return mongoTemplate.aggregate(aggregation, mongoTemplate.getCollectionName(UserAttributesEntity.class), Map.class)
.map(result -> Long.valueOf(result.get("count").toString()))
.next()