Arhn - архитектура программирования

mongoDB: как отменить $unwind

Рассмотрим этот набор результатов тестов:

[{
    _id: ObjectId(...),
    name: "Test1",
    acts: [
    {
        name: "act1", 
        tests: [
            {name: "test1", result: true}, 
            {name: "test2", result: true}]
    }]
},
{
    _id: ObjectId(...),
    name: "Test2",
    acts: [
    {
        name: "act1", 
        tests: [
            {name: "test1", result: true}, 
            {name: "test2", result: false}]
    }, 
    {
        name: "act2", 
        tests: [
            {name: "test3", result: true}]
    }]
}]

Я пытаюсь использовать агрегации для создания вычисляемого поля с суммой всех результатов теста, я хочу что-то вроде этого:

[{
    _id: ObjectId(...),
    name: "Test1",
    result: true, //new aggregated value
    acts: [
    {
        name: "act1", 
        result: true, //new aggregated value
        tests: [
            {name: "test1", result: true}, 
            {name: "test2", result: true}]
    }]
},
{
    _id: ObjectId(...),
    name: "Test2",
    result: false, //new aggregated value
    acts: [
    {
        name: "act1", 
        result: false, //new aggregated value
        tests: [
            {name: "test1", result: true}, 
            {name: "test2", result: false}]
    }, 
    {
        name: "act2", 
        result: true, //new aggregated value
        tests: [
            {name: "test3", result: true}]
    }]
}]

Я пробовал использовать агрегат и $unwind, $project и $group:

aggregate([
  {$unwind: "$acts"},
  {$unwind: "$acts.tests"},
  {$project: {name: 1, acts: 1, failed: {$cond: {if: {$eq: ["$acts.tests.test", "true" ]}, then: 0, else: 1}}}},
  {$group: {_id: "$_id", failedCount: {$sum: "$failed"}, acts: {$push: "$acts.tests"}}}
])

Но я не могу заставить его отменить операцию $unwind, я получаю только результирующую структуру данных, отличающуюся от оригинала. Можно ли добиться того, чтобы результат выглядел точно так же, как исходная коллекция, но с новыми агрегированными значениями?

/гемигспам


Ответы:


1

Существует особая хитрость в том, как это обрабатывается, но, во-первых, если у вас есть MongoDB 2.6 или выше, вы можете делать то, что хотите, без использования $unwind. Это может быть очень удобно для производительности, если вы обрабатываете много документов.

Ключевыми операторами здесь являются $map, которые обрабатывают массивы на месте и оператор $allElementsTrue, который будет оценивать ваши поля "результат". Использование «карты» здесь позволяет тестировать внутренний массив «тесты», чтобы увидеть, где все поля «результата» соответствуют истинному условию. В случае внешнего массива этот «результат» может быть помещен в те документы, которые вам нужны, и, конечно, полная оценка документа следует тем же правилам:

db.test.aggregate([
    { "$project": {
        "name": 1,
        "result": {
            "$allElementsTrue": {
                "$map": {
                    "input": "$acts",
                    "as": "act",
                    "in": {
                        "$allElementsTrue": {
                            "$map": {
                                 "input": "$$act.tests",
                                 "as": "test",
                                 "in": "$$test.result"
                            }
                        }
                    }
                }
            }
        },
        "acts": {
            "$map": {
                 "input": "$acts",
                 "as": "act",
                 "in": {
                    "name": "$$act.name",
                    "result": {
                        "$allElementsTrue": {
                            "$map": {
                                "input": "$$act.tests",
                                "as": "test",
                                "in": "$$test.result"
                            }
                        }
                    },
                    "tests": "$$act.tests"
                 }
            }
        }
    }}
])

Способ сделать это в более ранних версиях требует, чтобы вы $group назад на два шага, чтобы «перестроить» массивы, снова выполняя тесты для этих «результирующих» полей. Другое отличие заключается в использовании оператора $min как false. будет считаться меньшим значением, чем true, и оценивается по той же концепции "allElements":

db.test.aggregate([
    { "$unwind": "$acts" },
    { "$unwind": "$acts.tests" },
    { "$group": {
        "_id": {
            "_id": "$_id",
            "name": "$name",
            "actName": "$acts.name"
        },
        "result": { "$min": "$acts.tests.result" },
        "tests": {
           "$push": {
               "name": "$acts.tests.name",
               "result": "$acts.tests.result"
           }
        }
    }},
    { "$group": {
        "_id": "$_id._id",
        "name": { "$first": "$_id.name" },
        "result": { "$min": "$result" },
        "acts": {
            "$push": {
                "name": "$_id.actName",
                "result": "$result",
                "tests": "$tests"
            }
        }
    }}
])
06.08.2014
  • Я считаю, что оператор $group более ценен в этом сценарии из-за его гибкости. 03.10.2015
  • Новые материалы

    Коллекции публикаций по глубокому обучению
    Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

    Представляем: Pepita
    Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

    Советы по коду Laravel #2
    1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

    Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
    Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

    3 способа решить квадратное уравнение (3-й мой любимый) -
    1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

    Создание VR-миров с A-Frame
    Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

    Демистификация рекурсии
    КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..