Подсчитать количество экземпляров строки в поле в документах, сгруппированных в другом поле в MongoDB? - PullRequest
2 голосов
/ 08 марта 2020

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

Пример данных:

{
    "flightNum": "DL1002",
    "status": "On time",
    "date": 20191001
},
{
    "flightNum": "DL1002",
    "status": "Delayed",
    "date": 20191002
},
{
    "flightNum": "DL1002",
    "status": "On time",
    "date": 20191003
},
{
    "flightNum": "DL1002",
    "status": "Cancelled",
    "date": 20191004
},
{
    "flightNum": "DL952",
    "status": "On time",
    "date": 20191003
},
{
    "flightNum": "DL952",
    "status": "On time",
    "date": 20191004
}

Я хочу конвейер агрегации, который может сказать мне, для каждого рейса (группа по flightNum), сколько рейсов было «вовремя», «отложено» или «отменено».

Желаемый ответ:

{
    "flightNum": "DL1002",
    "numOnTime": 2,
    "numCancelled": 1,
    "numDelayed": 1
},
{
    "flightNum": "DL952",
    "numOnTime": 2
}

На самом деле не имеет значения имена полей, поскольку они есть в одном документе. Я обнаружил, что могу сделать это с помощью оператора $ cond , но это потребует от меня жесткого кодирования ожидаемых значений поля «status». Для этого произвольного примера не так много значений, но если будет добавлен другой статус, я бы не хотел обновлять запрос. Так как в Mon go так много изящных трюков, я чувствую, что есть способ достичь этого.

1 Ответ

3 голосов
/ 08 марта 2020

Вы можете попробовать запрос ниже:

db.collection.aggregate([
    /** Group all docs based on flightNum & status & count no.of occurances */
    {
        $group: {
            _id: {
                flightNum: "$flightNum",
                status: "$status"
            },
            count: {
                $sum: 1
            }
        }
    },
    /** Group on flightNum & push an objects with key as status & value as count */
    {
        $group: {
            _id: "$_id.flightNum",
            status: {
                $push: {
                    k: "$_id.status",
                    v: "$count"
                }
            }
        }
    },
    /** Recreate status field as an object of key:value pairs from an array of objects */
    {
        $addFields: {
            status: {
                $arrayToObject: "$status"
            }
        }
    },
    /** add flightNum inside status object */
    {
        $addFields: {
            "status.flightNum": "$_id"
        }
    },
    /** Replace status field as new root for each doc in coll */
    {
        $replaceRoot: {
            newRoot: "$status"
        }
    }
])

Тест: MongoDB-Playground

...