гистограмма результат гистограммы - PullRequest
1 голос
/ 11 июля 2019

Я сгенерировал гистограмму с помощью следующей команды:

db.mydb.aggregate([{ $bucketAuto: { groupBy: "$userId", buckets: 1e9 } }])

Если у меня менее 1 миллиарда уникальных пользователей (и достаточно памяти), это дает мне количество документов для каждого пользователя.

User   Docs
=====  ====
userA  3
userB  1
userC  5
userD  1

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

Результат будет выглядеть так:

Docs  Users
====  =====
1     2
2     0
3     1
4     0
5     1

Есть ли простой, функциональный способ сделать это в MongoDB?

1 Ответ

1 голос
/ 11 июля 2019

Одна вещь, с которой вы можете начать, это просто $ group stage:

db.col.aggregate([
    {
        $group: {
            _id: "$docs",
            count: { $sum: 1 }
        }
    },
    {
        $project: {
            _id: 0,
            docs: "$_id",
            users: "$count"            
        }
    },
    {
        $sort: { docs: 1 }
    }
])

Это даст вам следующий результат:

{ "docs" : 1, "users" : 2 }
{ "docs" : 3, "users" : 1 }
{ "docs" : 5, "users" : 1 }

Тогда документы без пользователейнедостающая часть.Вы можете добавить их либо из своего приложения, либо из MongoDB (показано ниже):

db.col.aggregate([
    {
        $group: {
            _id: "$docs",
            count: { $sum: 1 }
        }
    },
    {
        $group: {
            _id: null,
            histogram: { $push: "$$ROOT" }
        }
    },
    {
        $project: {
            values: {
                $map: { 
                    input: { $range: [ { $min: "$histogram._id" }, { $add: [ { $max: "$histogram._id" }, 1 ] } ] },
                    in: {
                        docs: "$$this",
                        users: {
                            $let: {
                                vars: {
                                    current: { $arrayElemAt: [ { $filter: { input: "$histogram", as: "h", cond: { $eq: [ "$$h._id", "$$this" ] } } }, 0 ] }
                                },
                                in: {
                                    $ifNull: [ "$$current.count", 0 ]
                                }
                            }
                        }
                    } 
                }
            }
        }
    },
    {
        $unwind: "$values"
    },
    {
        $replaceRoot: {
            newRoot: "$values"
        }
    }
])

Идея заключается в том, что мы можем $group по null, который создает один документ, содержащий все документы из предыдущего этапа.Зная значения $min и $max, мы можем сгенерировать $ диапазон чисел и $ map , которые варьируются либо в существующие счетчики, либо в значение по умолчанию, равное 0. Тогда мы можем использовать $ unwind и $ replaceRange , чтобы получить одну точку гистограммы на документ.Выход:

{ "docs" : 1, "users" : 2 }
{ "docs" : 2, "users" : 0 }
{ "docs" : 3, "users" : 1 }
{ "docs" : 4, "users" : 0 }
{ "docs" : 5, "users" : 1 }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...