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

Posted

技术标签:

【中文标题】MongoDB Aggregation - 如何使用 spring-data-mongodb 将查询表达式应用到匹配阶段?【英文标题】:MongoDB Aggregation - How can i apply query expression into match stage using spring-data-mongodb? 【发布时间】:2021-12-06 23:59:05 【问题描述】:

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

示例实体

@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"
    

预期的查询表达式

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

$match 的 MongoDB 聚合查询如下所示,但通过 spring mongo db api 不可用:

 
    $expr: 
     
        "$and": [
            "$gt": ["$attributes.age", 40]
        , 
            "$eq": ["$attributes.name", "Name2"]
        ] 
    

我这里有什么遗漏吗?

库使用:org.springframework.data:spring-data-mongodb:3.1.1

【问题讨论】:

【参考方案1】:

您可以实现自己的AggregationOperation 来处理您不同的情况。 我自己的代码没试过,不过应该是这样的:

AggregationOperation myMatch (List<Document> conditions) 

    return new AggregationOperation() 

        @Override
        public String getOperator() 
            return "$match";
        

        @Override
        public Document toDocument(AggregationOperationContext context) 
            return new Document("$match",
                    new Document("$expr",
                            new Document("$and", conditions)
                    )
            );
        
    ;

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

void callMyMatch() 
    myMatch(List.of(
        new Document("$gt", List.of("$attributes.age", 40)),
        new Document("$eq", List.of("$attributes.name", "Name2"))
    ));

【讨论】:

谢谢@orid。是的,我可以执行上述方法,甚至我也可以尝试根据查询动态创建 Criteria 对象,但我会期待一些具有嵌套条件的复杂查询,因此希望我是否可以简单地使用 SPEL 来评估查询表达式?类似问题:***.com/questions/69635474/… 寻找一种直接传入表达式而不像上面那样构建它的方法:"((attributes.name == 'Name1' &amp;&amp; attributes.age &gt; 40) OR (attributes.location == 'IN'))"

以上是关于MongoDB Aggregation - 如何使用 spring-data-mongodb 将查询表达式应用到匹配阶段?的主要内容,如果未能解决你的问题,请参考以下文章

mongodb Aggregation聚合操作之$sort

MongoDB 聚合管道(Aggregation Pipeline)

mongodb Aggregation聚合操作之$bucket

mongodb Aggregation聚合操作之$facet

mongoDB: Aggregation - 是不是有相当于原生 node.js 驱动程序的 $lookup 连接?

MongoDB $reduce(aggregation) 组与数组中嵌套文档的总和并按组计数