MongoDB聚合-如何使用spring-data-mongodb将查询表达式应用到匹配阶段?

zbdgwd5y  于 2022-12-12  发布在  Go
关注(0)|答案(3)|浏览(178)

我的文档中包含动态字段,我需要根据给定的复杂查询条件查找匹配记录的计数

示例实体

  1. @Document(collection = "UserAttributes")
  2. public class UserAttributesEntity {
  3. @Id
  4. @Getter
  5. private String id;
  6. @NotNull
  7. @Size(min = 1)
  8. @Getter @Setter
  9. private String userId;
  10. @NotNull
  11. @Getter @Setter
  12. private Map<String, Object> attributes = new HashMap<>();
  13. }

示例数据

  1. {
  2. "_id" : ObjectId("6164542362affb14f3f2fef6"),
  3. "userId" : "89ee6942-289a-48c9-b0bb-210ea7c06a88",
  4. "attributes" : {
  5. "age" : 61,
  6. "name" : "Name1"
  7. }
  8. },
  9. {
  10. "_id" : ObjectId("6164548045cc4456792d5325"),
  11. "userId" : "538abb29-c09d-422e-97c1-df702dfb5930",
  12. "attributes" : {
  13. "age" : 40,
  14. "name" : "Name2",
  15. "location" : "IN"
  16. }
  17. }

需要查询表达式

  1. "((attributes.name == 'Name1' && attributes.age > 40) OR (attributes.location == 'IN'))

$match的MongoDB聚合查询如下所示,但无法通过spring mongo db API获得相同的查询:

  1. {
  2. $expr:
  3. {
  4. "$and": [{
  5. "$gt": ["$attributes.age", 40]
  6. }, {
  7. "$eq": ["$attributes.name", "Name2"]
  8. }]
  9. }
  10. }

我错过什么了吗?
库使用:数据org.springframework.data库:3.1.1

ao218c7q

ao218c7q1#

您可以实现自己的AggregationOperation来处理各种情况。我还没有尝试过自己的代码,但应该是这样的:

  1. AggregationOperation myMatch (List<Document> conditions) {
  2. return new AggregationOperation() {
  3. @Override
  4. public String getOperator() {
  5. return "$match";
  6. }
  7. @Override
  8. public Document toDocument(AggregationOperationContext context) {
  9. return new Document("$match",
  10. new Document("$expr",
  11. new Document("$and", conditions)
  12. )
  13. );
  14. }
  15. };
  16. }

并以这种方式调用它(以匹配您问题查询):

  1. void callMyMatch() {
  2. myMatch(List.of(
  3. new Document("$gt", List.of("$attributes.age", 40)),
  4. new Document("$eq", List.of("$attributes.name", "Name2"))
  5. ));
  6. }
展开查看全部
ve7v8dk2

ve7v8dk22#

这个项目阶段允许我们使用查询表达式,我把我的方法转换到下面来达到结果:

  1. private Mono<Long> aggregate() {
  2. final Aggregation aggregation = Aggregation
  3. .newAggregation(
  4. Aggregation.project("userAttributes.playerLevel", "userAttributes.name")
  5. .andExpression("((userAttributes.name == 'Name1' && userAttributes.age > 40) OR (userAttributes.location == 'IN'))")
  6. .as("result"),
  7. Aggregation.match(Criteria.where("result").is(true)),
  8. Aggregation.group().count().as("count"));
  9. return mongoTemplate.aggregate(aggregation, mongoTemplate.getCollectionName(UserAttributesEntity.class), Map.class)
  10. .map(result -> Long.valueOf(result.get("count").toString()))
  11. .next()
  12. }
83qze16e

83qze16e3#

在spring-data-mongodb库中仍然不支持$expr操作符。但是有一个使用MongoTemplate的解决方案来解决这个问题-
Aggregation.match()提供了一个重载方法,它接受AggregationExpression作为参数。

$match运算子的AggregationExpression使用范例-

  1. Aggregation aggregationQuery = Aggregation.newAggregation(Aggregation.match(AggregationExpression.from(MongoExpression.create("'$expr': { '$gte': [ '$foo', '$bar'] }"))));
  2. mongoTemplate.aggregate(aggregationQuery, Entity.class);

以上代码相当于query -

  1. db.collection.aggregate([{"$match": {"$expr": {"$gte: ["$foo", "$bar"]}}}])

问题的代码应该是这样的-

  1. Aggregation aggregationQuery = Aggregation.newAggregation(Aggregation.match(AggregationExpression.from(MongoExpression.create("'$expr': { '$and': [{ '$gt': ['$attributes.age', 40] }, { '$eq': ['$attributes.name', "Name2"] }] }"))));
  2. mongoTemplate.aggregate(aggregationQuery, Entity.class);

相关问题