Фильтровать глубоко вложенный список с помощью операций агрегирования Spring data

У меня есть следующий документ

[ {
        "pageName": "Content_2",
        "domain": "bingo.com",
        "locale": "en-us",
        "contents": [
            {
                "contentName": "Template_2",
                "fields": [
                    {
                        "title": "Company Name"                     
                    },
                    {
                        "title": "Designation"
                    }
                ]
            }
        ]
    },
{
        "version": 2,
        "pageName": "Content_3",
        "domain": "bingo.com",
        "locale": "en-in",
        "contents": [
            {
                "contentName": "Template_2",
                "fields": [
                    {
                        "title": "Company Name"                          
                    },
                    {
                        "title": "Designation"
                    }
                ]
            }
        ]
    }]

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

Aggregation aggregation = newAggregation(
                    match(
                        where("domain").is(domain)
                        .and("contents.contentName").is(templateName)
                        .and("locale").in(criteria.getLocales())), 
                        project().and(new AggregationExpression() {
                        @Override
                        public Document toDocument(AggregationOperationContext aggregationOperationContext) {
                            DBObject filterExpression = new BasicDBObject();
                            filterExpression.put("input", "$contents.fields");
                            filterExpression.put("as", "field");
                            filterExpression.put("cond",
                                    new BasicDBObject("$eq", Arrays.<Object>asList("$$field.title", "Company Name")));
                            return new Document("$filter", filterExpression);
                        }

                }).as("field"));
AggregationResults<MyClass> list = mongoOperations.aggregate(aggregation, MyClass.class,
                MyClass.class);

Он возвращает все атрибуты как null. Пожалуйста, направляйте. Я новичок в MongoDB. Заранее спасибо;


person Pawan Kumar    schedule 24.01.2019    source источник


Ответы (1)


Вы можете использовать это объединение

db.collection.aggregate([
        { $unwind: '$contents' },
        { $match: { "locale": "en-us", 
"domain": "bingo.com", "contents.contentName": "Template_2"} },
        { $unwind: '$contents.fields' },
        { $match: { 'contents.fields.title' : "Company Name" } },
        { $group: { _id: '$_id', 
              fields: { $push: { title: '$contents.fields.title'}}, 
              "locale" : {$first: "$locale"},
              "domain" : {$first: "$domain"},
              "pageName" : {$first: "$pageName"},
              'contentName': {$first: '$contents.contentName'}
              }
        },
        { $group: { _id: '$_id', 
         "locale" : {$first: "$locale"},
         "domain" : {$first: "$domain"},
         "pageName" : {$first: "$pageName"},
         contents: { $push: { "contentName": '$contentName', "fields": '$fields' }}, 
        }}
    ])

Или просто примените это. Мои извинения, если я допустил ошибку в синтаксисе, но постараюсь сделать все правильно

Aggregation aggregation = newAggregation(
                    unwind("contents),
                    match(
                         where("$domain").is(domain)
                        .and("$contents.contentName").is(templateName)
                        .and("$locale").in(criteria.getLocales())
                       ),
                    unwind("$contents.fields"),
                    match(where("$contents.fields.title").is(title)),
                    group("_id")
                     .push("$contents.fields.title").as("fields")
                     .push("$locale").as("locale")
                     .push("$domain").as("domain")
                     .push("$pageName").as("pageName")
                     .push("$contents.contentName").as("contentName"),
                 group("_id")
                 .push("locale").as("locale")
                 .push("domain").as("domain")
                 .push("pageName").as("pageName")
                 .push(new BasicDBObject
                   ("contentName", "$contentName").append
                   ("fields", "$fields").as("contents"))
                );
AggregationResults<MyClass> list = mongoOperations.aggregate(aggregation, MyClass.class,
                MyClass.class);

Run It Ваш результат ждет Вас...

person Ashok    schedule 25.01.2019
comment
Спасибо друг. Я попробую. Единственное, что беспокоит меня, снова нажимая атрибуты, потому что есть много других полей, которые я не показал, просто вопрос по существу. Я попробовал этот подход с раскруткой, но код стал беспорядочным. Я надеялся на что-то короткое. - person Pawan Kumar; 25.01.2019
comment
Эй, используйте его и дайте идею, чтобы сократить его: - db.locations.aggregate([{$unwind:'$contents'},{$match:{locale:en-us,domain:bingo.com,contents.contentName :Template_2}},{$unwind:'$contents.fields'},{$match:{'contents.fields.title':название компании}},{$group:{_id:'$_id',поля:{ $push:{title:'$contents.fields.title'}},root:{$first:$$ROOT}}},{$group:{_id:'$_id',root:{$first:'$ root'},contents:{$push:{contentName:'$contentName',fields:'$fields'}},}},{$replaceRoot:{newRoot:{$mergeObjects:[$root,{contents:'$ содержание'}]}}}]) - person Ashok; 28.01.2019