MongoDB: сумма значений в объекте без MapReduce - PullRequest
0 голосов
/ 24 ноября 2018

У меня есть коллекция объектов:

{
    "_id" : "01",
    "properties" : {
        "colors" : {
            "red" : 0.8891772,
            "blue" : 0.7580757,
            "green" : 0.4345628,
            "white" : 0.7373822,
            "black" : 0.93228924,
            ...
            "purple" : 0.83328924,
    }
}

У цветов есть еще много ключей, которые были показаны выше.Кроме того, не все объекты имеют одинаковые ключи, например, объект может вообще не иметь properties.colors.red.

Мне нужно суммировать значения цветовых клавиш так, чтобы результат выглядел:

/* 1 */
{
    "key" : "Red",
    "value" : 2723.1982
}

/* 2 */
{
    "key" : "Blue",
    "value" : 972172.271
}

...

Где значения являются суммой значений для этого цвета.

РЕДАКТИРОВАТЬ

На самом деле лучше, чем просто сумма для каждого свойства.цвета будут средним значением сумм по общему количеству документов в исходных коллекциях.

Так, например:

{
    "_id" : "01",
    "properties" : {
        "colors" : {
            "red" : 2.0,
            "blue" : 4.0,
    }
}

{
    "_id" : "02",
    "properties" : {
        "colors" : {
            "red" : 2.0,
            "black" : 8.0,
    }
}

Должно привести к:

/* 1 */
{
    "key" : "red",
    "value" : 2.0
}

/* 2 */
{
    "key" : "blue",
    "value" : 2.0
}

/* 3 */
{
    "key" : "black",
    "value" : 4.0
}

1 Ответ

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

Вы должны запустить два одновременных конвейера: один, который просто считает все документы, а второй, который агрегирует по цвету.Вы можете сделать это, используя $ facet .Первый конвейер довольно прост: вам просто нужно $ count , чтобы получить количество элементов.Вы можете начать вторую агрегацию с $ objectToArray , который преобразует вложенный объект в массив ключей и значений (поля k и v).Затем вы можете запустить $ unwind для этого массива, чтобы получить по одному документу для каждой записи, чтобы можно было использовать $ group и $sum.Тогда вам просто нужно $project, чтобы изменить окончательный результат.Наконец, вам нужно $ делить , чтобы разделить каждый результат на количество элементов в коллекции.Попробуйте:

db.col.aggregate([
    {
        $facet: {
            total: [ { $count: "value" } ],
            agg: [
                {
                    $project: {
                        colors: {
                            $objectToArray: "$properties.colors"
                        }
                    }
                },
                {
                    $unwind: "$colors"
                },
                {
                    $group: {
                        _id: "$colors.k",
                        v: { $sum: "$colors.v" }
                    }
                }
            ]
        }
    },
    {
        $unwind: "$total"
    },
    {
        $unwind: "$agg"
    },
    {
        $project: {
            _id: 0,
            key: "$agg._id",
            value: { $divide: [ "$agg.v", "$total.value" ] }
        }
    }
])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...