直方图直方图的结果

时间:2019-07-11 02:16:03

标签: javascript mongodb aggregation-framework

我通过以下命令生成了直方图:

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

假设我的唯一身份用户少于10亿(并且有足够的内存),那么我可以计算出每个用户的文档数。

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

我想获取此直方图的结果,并枢轴计算每个文档计数的用户数。

结果如下:

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

在MongoDB中是否有一种简单,实用的方法来做到这一点?

2 个答案:

答案 0 :(得分:1)

您可以从一开始的简单$group阶段开始:

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{ "docs" : 1, "users" : 2 } { "docs" : 2, "users" : 0 } { "docs" : 3, "users" : 1 } { "docs" : 4, "users" : 0 } { "docs" : 5, "users" : 1 } 的值,我们可以生成一个$range的数字和$map,它们的范围是现有计数或默认值0。然后我们可以使用{{3 }}和$unwind以获得每个文档的单个直方图点。输出:

@import '../scss/vars';

答案 1 :(得分:0)

mickl's answer绝对使我朝着正确的方向前进。特别是,在该用例中,使用$group是对$bucketAuto的一个很好的改进。分层直方图的技巧只是在同一$group中多次使用aggregate阶段。我想这在事后看来很明显。

完整的解决方案在这里:

const h2 = db.mydb.aggregate([
    { $group: { _id: "$userId", count: { $sum: 1 } } },
    { $group: { _id: "$count", count: { $sum: 1 } } },
    { $project: { docs: "$_id", users: "$count" } },
    { $sort: { docs: +1 } }
])