我已经通过以下命令生成了一个直方图:
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中有没有一种简单、实用的方法来实现这一点呢?
发布于 2019-07-11 13:17:37
你可以从简单的$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"
}
}
])这里的想法是,我们可以通过null生成包含前一阶段的所有文档的单个文档。知道了$min和$max的值,我们就可以生成一个$range of numbers和$map,它的范围既可以是现有的计数,也可以是默认值0。然后,我们可以使用$unwind和$replaceRange来获得每个文档的单个直方图点。输出:
{ "docs" : 1, "users" : 2 }
{ "docs" : 2, "users" : 0 }
{ "docs" : 3, "users" : 1 }
{ "docs" : 4, "users" : 0 }
{ "docs" : 5, "users" : 1 }发布于 2019-12-04 11:05:50
mickl's answer绝对让我朝着正确的方向前进。特别是,在这个用例中,使用$group是对$bucketAuto的一个很好的改进。对直方图进行分层的诀窍是在同一个aggregate中多次使用$group阶段。我想这在事后看来是显而易见的。
完整的解决方案在这里:
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 } }
])https://stackoverflow.com/questions/56980789
复制相似问题