用户投影字段作为 Spring Boot 2 和 MongoDB 中 MatchOperation 的标准

User projected field as criteria for a MatchOperation in Spring Boot 2 and MongoDB

我花了几个小时寻找一种方法来做到这一点,但我没有找到任何有用的方法。

我会尽量简短。我有几个步骤的聚合。第一步我分组,然后我用表达式投影几个字段(进行一些计算),最后我想使用这些投影字段(我的计算结果)作为下一个匹配阶段的条件:

    Cond condOperation = ConditionalOperators.when(Criteria.where("productRulesValues.maxTerm").lte("$availableYears"))
            .thenValueOf("$productRulesValues.maxTerm")
            .otherwise("$availableYears");

    TypedAggregation<ProductRulesValues> aggregationProducts = Aggregation.newAggregation(ProductRulesValues.class,
            Aggregation.group("productType")
                    .last("$$ROOT").as("productRulesValues"),
            project("productRulesValues")
                    .andExpression("productRulesValues.maxAge - [0]", formHipooWizard.getAge()).as("availableYears"),
            project("productRulesValues")
                    .and(condOperation).as("duration"),
            new MatchOperation(Criteria.where("productRulesValues.maxTerm").is("$duration"))
    );

最接近我正在寻找的答案是 ,但它使用了 DBObject 的旧方法。

我试过用 org.bson.Document 改变 DBObject 的方法,因为它现在使用的是运气不好(它抱怨 $where 子句)。参考:

https://docs.spring.io/spring-data/mongodb/docs/current/api/org/springframework/data/mongodb/core/query/CriteriaDefinition.html

我不太明白的一件事是,当我定义第一个条件时,使用文档属性和投影属性没有问题。

如果不是:

new MatchOperation(Criteria.where("productRulesValues.maxTerm").is("$duration")

我用文字过滤持续时间,它的工作原理非常棒,因此持续时间具有正确的内存值:

new MatchOperation(Criteria.where("duration").is(30)

有什么解决方法吗?

谢谢!

这是预期的行为。

第一个条件中的聚合表达式允许您比较文档字段。因此在 3.6 之前,所有匹配查询都与静态值和文档字段进行比较。

从 3.6 开始,您必须使用特殊运算符 $expr,它允许在匹配查询中使用聚合表达式。

spring 尚不支持 $expr。

您必须使用投影来添加包含比较的新字段,然后使用匹配操作和额外的投影来删除比较字段。

Cond condOperation = ConditionalOperators.when(Criteria.where("productRulesValues.maxTerm").lte("$availableYears"))
        .thenValueOf("$productRulesValues.maxTerm")
        .otherwise("$availableYears");

TypedAggregation<ProductRulesValues> aggregationProducts = Aggregation.newAggregation(ProductRulesValues.class,
        Aggregation.group("productType")
                .last("$$ROOT").as("productRulesValues"),
        project("productRulesValues")
                .andExpression("productRulesValues.maxAge - [0]", formHipooWizard.getAge()).as("availableYears"),
        project("productRulesValues")
                .and(condOperation).as("duration").and(ComparisonOperators.Eq.valueOf("productRulesValues.maxTerm").equalOf("duration")).as("comp"),
        new MatchOperation(Criteria.where("comp").is(true)),
        project().andExclude("comp");
);

请注意,从 3.4 开始支持带排除项的项目。