我通过以下命令生成了直方图:
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中是否有一种简单,实用的方法来做到这一点?
答案 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 } }
])