我想编写一个聚合查询来计算ARPU (每个用户的平均收入),但是我一直在讨论如何使用数据来分离模型,我知道我可以使用$lookup连接到模型中,但是我不能以这种方式计算所有的用户。
这些是我的模型:
// User:
{
_id,
username: String,
os: String
}和
// Payment:
{
_id,
user: ObjectId,
price: Number
}我需要计算所有付款的总和除以所有用户的数量。
在此之后,我需要将它们按OS分组,即拥有os='os1'的用户支付的所有款项之和除以每个操作系统拥有os='os1'的所有用户的数量。
编辑
例如,用户的示例数据是:
{
"_id" : ObjectId("5b77fdffcbbd830011dbc04e"),
"username" : "user1",
"os" : "android"
},
{
"_id" : ObjectId("5b7856756aaf56001120816b"),
"username" : "user2",
"os" : "android"
},
{
"_id" : ObjectId("5b824fa7234d1b0010310522"),
"username" : "user3",
"os" : "android"
},
{
"_id" : ObjectId("5b8a242444074c0074b8a318"),
"username" : "user4",
"os" : "ios"
},
{
"_id" : ObjectId("5b7801b0cbbd830011dbc050"),
"username" : "user5",
"os" : "ios"
}支付的样本数据如下:
{
"_id" : ObjectId("5bab61b617df7f173037fb1b"),
"user" : ObjectId("5b77fdffcbbd830011dbc04e"), // user1
"price" : 5
},
{
"_id" : ObjectId("5bad4f980ab23100119300ec"),
"user" : ObjectId("5b77fdffcbbd830011dbc04e"), // user1
"price" : 10
},
{
"_id" : ObjectId("5bad525edeed4e0011286842"),
"user" : ObjectId("5b7856756aaf56001120816b"), // user2
"price" : 5
},
{
"_id" : ObjectId("5bad525edeed4e0011286848"),
"user" : ObjectId("5b8a242444074c0074b8a318"), // user4
"price" : 5
},
{
"_id" : ObjectId("5bad525edeed4e0011286849"),
"user" : ObjectId("5b8a242444074c0074b8a318"), // user4
"price" : 15
}我的预期输出是一个使用聚合查询实现的数字。
首先,我想要的是每个用户的平均收入:
ARPU: {sum of all payments} / {count of all users} = 40 / 5 = 8
如果我能做到这一点,那么我需要对每个操作系统进行分组:
ios-ARPU: {sum of payments ios users made} / {count of ios users} = 20 / 2 = 10
android-ARPU: {sum of payments android users made} / {count of android usrs} = 20 / 3 = 6.67
发布于 2018-12-26 13:41:46
您可以从$lookup开始,然后使用$reduce计算每个用户的totalPayments。然后您可以通过$group by null获得包含用户总数和总付款的单个文档。要获得ARPU,最后一步需要$divide。
db.users.aggregate([
{
$lookup: {
from: "payments",
localField: "_id",
foreignField: "user",
as: "payments"
}
},
{
$project: {
_id: 1,
os: 1,
totalPayments: {
$reduce: {
input: "$payments",
initialValue: 0,
in: {
$add: [ "$$value", "$$this.price" ]
}
}
}
}
},
{
$group: {
_id: null,
totalUsers: { $sum: 1 },
totalPayments: { $sum: "$totalPayments" }
}
},
{
$project: {
arpu: { $divide: [ "$totalPayments", "$totalUsers" ] }
}
}
])产出:{ "arpu" : 8 }
要获得arpu的每一个操作系统,您只需要通过$group通过$os
{
$group: {
_id: "$os",
totalUsers: { $sum: 1 },
totalPayments: { $sum: "$totalPayments" }
}
}指纹:
{ "_id" : "ios", "arpu" : 10 }
{ "_id" : "android", "arpu" : 6.666666666666667 }发布于 2018-12-26 14:30:44
利用$facet的使用,在$lookup阶段之后在一个管道中获得这两组计算。
下面演示如何将$facet用于上述聚合操作:
db.getCollection('Payment').aggregate([
{ "$lookup": {
"from": "users",
"localField": "user",
"foreignField": "_id",
"as": "user"
} },
{ "$addFields": {
"user": { "$arrayElemAt": ["$user", 0] }
} },
{ "$facet": {
"users": [
{ "$group": {
"_id": null,
"ARPU": { "$avg": "$price" }
} }
],
"os": [
{ "$group": {
"_id": "$user.os",
"ARPU": { "$avg": "$price" }
} },
{ "$group": {
"_id": null,
"avgs": {
"$push": {
"k": { "$concat": ["ARPU", "-", "$_id"] },
"v": "$ARPU"
}
}
} },
{ "$replaceRoot": {
"newRoot": { "$arrayToObject": "$avgs" }
} }
]
} }
])这将为给定的示例文档产生如下结果:
{
"users" : [
{
"_id" : null,
"ARPU" : 8.0
}
],
"os" : [
{
"ios-ARPU" : 10.0,
"android-ARPU" : 6.66666666666667
}
]
}https://stackoverflow.com/questions/53929618
复制相似问题