我有一个名为 UserRecords 的 MongoDb 集合。它存储了我们用户的所有记录,每个用户可以有很多记录。
我正在尝试计算一些与每个用户的记录数相关的基本统计数据。
具体来说,我想要每个用户的记录数的平均值、中位数和众数。
到目前为止,我有一个查询,该查询按 User_Id (uid) 对所有 UserRecords 进行分组,并计算每个用户的 UserRecords 数量。
db.UserRecords.aggregate([
{$group:
{_id:{"uid":"$uid"},
count:{$sum:1}}}
])
我的查询产生如下所示的结果:
{
"_id" : {
"uid" : UUID("f22880a8-94d2-4524-a974-a2e500e2c2a2")
},
"count" : 100
}
{
"_id" : {
"uid" : UUID("1b3a3b81-d107-4345-8df5-a5ef00e23598")
},
"count" : 200
}
我需要查询来计算所有“计数”值的平均值。例如,假设仅产生上述结果 2 个组。我需要我的查询执行 (100 + 200) / 2 = 150 并将该值 150 打印到控制台。
有谁知道我可以在查询中添加什么来完成此操作?
*编辑,我理想的结果结构是:
{
"mean": 1000,
"median": 850
"mode": 900
}
正如评论中提到的,在数据库级别计算
median
和 mode
可能不是一个好习惯,但只是为了热情尝试这个。
顺便说一句,它计算
count
s 的累积 uid
的中位数和众数。
db.UserRecords.aggregate([
{
$group: {
_id: { "uid": "$uid" },
count: { $sum: 1 }
}
},
{
$group: {
_id: null,
mean: { $avg: "$count" },
numbers: { $push: "$count" }
}
},
{
$addFields: {
median: {
$function: {
body: function(numbers) {
if (numbers.length === 0) return 0;
numbers.sort(function(a, b) { return a - b; });
var half = Math.floor(numbers.length / 2);
if (numbers.length % 2) return numbers[half];
return (numbers[half - 1] + numbers[half]) / 2.0;
},
args: ["$numbers"],
lang: "js"
}
},
mode: {
$function: {
body: function(numbers) {
return Object.values(
numbers.reduce((count, e) => {
if (!(e in count)) {
count[e] = [0, e];
}
count[e][0]++;
return count;
}, {})
).reduce((numbers, v) => v[0] < numbers[0] ? numbers : v, [0, null])[1];
},
args: ["$numbers"],
lang: "js"
}
}
}
},
{
$project: {
_id: 0,
numbers: 0
}
}
]);
您可以
group
与 null
作为 _id
,在这种情况下,结果是单个
将累加器表达式应用于管道中每个文档的文档
根据 MongoDB 文档
如果您指定 _id 值为 null 或任何其他常量值,$group 阶段将计算所有输入文档作为一个整体的累积值
db.UserRecords.aggregate([
{
$group: {
_id: {"uid": "$uid"},
count: {$sum: 1}
},
},
{
// will result in a single document which contains sumaries of
// the previous groups data
$group: {
_id: null,
recordsCount: {$sum: '$count'}, // the number of records in the collection
usersCount: {$sum: 1}, // i.e "groups count"
}
},
{
$project: {
mean: {$divide: ['$recordsCount', '$usersCount']}
// ... you can add other measures here
}
}
])
对于大多数常见统计数据,例如计数、最小值、最大值、平均值,可以通过在
$sum
中使用
$min
、
$max
、
$avg
、
$group
来实现
对于模式,可以通过
$group
和 $count
计算,然后 $sort
+ $limit: 1
得到最大计数。
对于中位数,可以通过最新的MongoDB v7.0
$median
算子来实现。
样本在
$facet
:
db.collection.aggregate([
{
"$facet": {
"stat": [
{
$group: {
_id: null,
count: {
$sum: 1
},
min: {
$min: "$key"
},
max: {
$max: "$key"
},
mean: {
$avg: "$key"
},
median: {
$median: {
input: "$key",
method: "approximate"
}
}
}
}
],
"mode": [
{
"$group": {
"_id": "$key",
"count": {
"$sum": 1
}
}
},
{
$sort: {
count: -1
}
},
{
"$limit": 1
}
]
}
}
])
Mongo Playground(在撰写本文时,Mongo Playground 尚未支持 v7.0。您可能可以在 Playground 的后续版本中查看效果)