Spring MongoDB Aggregation Group - не удается правильно выполнить групповой запрос

У меня есть документ в MongoDB, который выглядит следующим образом.

{
    "_id" : ObjectId("5ceb812b3ec6d22cb94c82ca"),
    "key" : "KEYCODE001",
    "values" : [ 
        {
            "classId" : "CLASS_01",
            "objects" : [ 
                {
                    "code" : "DD0001"
                }, 
                {
                    "code" : "DD0010"
                }
            ]
        }, 
        {
            "classId" : "CLASS_02",
            "objects" : [ 
                {
                    "code" : "AD0001"
                }
            ]
        }
    ]
}

Я заинтересован в получении результата, как показано ниже.

{
    "classId" : "CLASS_01",
    "objects" : [ 
        {
            "code" : "DD0001"
        }, 
        {
            "code" : "DD0010"
        }
    ]
}

Для этого я придумал конвейер агрегации в Robo 3T, который выглядит следующим образом. И это работает, как ожидалось.

[
    {
        $match:{
            'key':'KEYCODE001'
        }
    },
    {
        "$unwind":{
            "path": "$values",
            "preserveNullAndEmptyArrays": true
        }
    },
    {
        "$unwind":{
            "path": "$values.objects",
            "preserveNullAndEmptyArrays": true
        }
    },
    {
        $match:{
            'values.classId':'CLASS_01'
        }
    },
    {
        $project:{
            'object':'$values.objects',
            'classId':'$values.classId'
        }
    },
    {
        $group:{
            '_id':'$classId',
            'objects':{
                $push:'$object'
            }
        }
    },
    {
        $project:{
            '_id':0,
            'classId':'$_id',
            'objects':'$$objects'
        }
    }
]

Теперь, когда я пытаюсь сделать то же самое в приложении SpringBoot, я не могу его запустить. В итоге у меня возникла ошибка java.lang.IllegalArgumentException: Invalid reference '$complication'!. Ниже приведено то, что я сделал на Java до сих пор.

final Aggregation aggregation = newAggregation(
        match(Criteria.where("key").is("KEYCODE001")),
        unwind("$values", true),
        unwind("$values.objects", true),
        match(Criteria.where("classId").is("CLASS_01")),
        project().and("$values.classId").as("classId").and("$values.objects").as("object"),
        group("classId", "objects").push("$object").as("objects").first("$classId").as("_id"),
        project().and("$_id").as("classId").and("$objects").as("objects")
);

Что я делаю неправильно? После исследования я обнаружил, что несколько полей в группе не работают или что-то в этом роде (см. этот вопрос). Итак, возможно ли то, что я сейчас делаю, в Spring Boot?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
0
1 954
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

После нескольких часов отладки + проб и ошибок было обнаружено, что следующее решение работает.

final Aggregation aggregation = newAggregation(
        match(Criteria.where("key").is("KEYCODE001")),
        unwind("values", true),
        unwind("values.objects", true),
        match(Criteria.where("values.classId").is("CLASS_01")),
        project().and("values.classId").as("classId").and("values.objects").as("object"),
        group(Fields.from(Fields.field("_id", "classId"))).push("object").as("objects"),
        project().and("_id").as("classId").and("objects").as("objects")
);

Все сводится к group(Fields.from(Fields.field("_id", "classId"))).push("object").as("objects") тому, что вводит org.springframework.data.mongodb.core.aggregation.Fields объект, который оборачивает список org.springframework.data.mongodb.core.aggregation.Field объектов. Внутри Field можно инкапсулировать имя поля и цель. Это привело к следующему конвейеру, который соответствует ожидаемому.

[
    {
        "$match" :{
            "key" : "KEYCODE001"
        }
    }, 
    {
        "$unwind" :{
            "path" : "$values", "preserveNullAndEmptyArrays" : true
        }
    }, 
    {
        "$unwind" :{
            "path" : "$values.objects", "preserveNullAndEmptyArrays" : true
        }
    }, 
    {
        "$match" :{
            "values.classId" : "CLASS_01"
        }
    }, 
    {
        "$project" :{
            "classId" : "$values.classId", "object" : "$values.objects"
        }
    }, 
    {
        "$group" :{
            "_id" : "$classId",
            "objects" :{
                "$push" : "$object"
            }
        }
    }, 
    {
        "$project" :{
            "classId" : "$_id", "objects" : 1
        }
    }
]

Кроме того, я понял, что нет необходимости использовать знак $ везде и всюду.

Благодаря вашему посту я нашел решение очень похожей проблемы!

EyedPeas 07.06.2020 14:20

Для тех, у кого есть похожая проблема, посмотрите эта почта.

EyedPeas 07.06.2020 14:26

Mongo может быть крутым и не модельным, но его язык запросов повсюду. Черт, я скучаю по SQL.

maaw 21.10.2020 23:30

Другие вопросы по теме