Спроецированное пользователем поле в качестве критерия для MatchOperation в Spring Boot 2 и MongoDB - PullRequest
0 голосов
/ 13 ноября 2018

Я потратил несколько часов на поиск способа сделать это, но я не нашел ничего полезного.

Я постараюсь быть кратким.У меня есть агрегация с несколькими шагами.В первом шаге я группирую, затем проецирую несколько полей с выражениями (для выполнения некоторых вычислений), и, наконец, я хочу использовать эти проецируемые поля (результат моих вычислений) в качестве условия на следующем этапе сопоставления:

    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"))
    );

Самый близкий ответ к тому, что я ищу, это https://stackoverflow.com/a/29280577/7206287, но он использует старый способ с DBObject.

Я пытался таким образом изменить DBObject с помощью org.bson.Document, так какэто то, что сейчас используется без удачи (он жалуется на предложение $ 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)

Любые обходные пути?

Спасибо!

1 Ответ

0 голосов
/ 14 ноября 2018

Это ожидаемое поведение.

Выражения агрегации, как в первом условии, позволяют сравнивать поля документа.Таким образом, до 3.6 все запросы на совпадение сравниваются со статическим значением и полем документа.

Начиная с 3.6, вы должны использовать специальный оператор $expr, который позволяет использовать выражения агрегации внутри запросов на совпадение.

$ 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.

...