首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >MongoDB聚合查询在用户和支付模型分离时计算ARPU

MongoDB聚合查询在用户和支付模型分离时计算ARPU
EN

Stack Overflow用户
提问于 2018-12-26 08:49:36
回答 2查看 201关注 0票数 3

我想编写一个聚合查询来计算ARPU (每个用户的平均收入),但是我一直在讨论如何使用数据来分离模型,我知道我可以使用$lookup连接到模型中,但是我不能以这种方式计算所有的用户。

这些是我的模型:

代码语言:javascript
复制
// User:
{
    _id,
    username: String,
    os: String
}

代码语言:javascript
复制
// Payment:
{
    _id,
    user: ObjectId,
    price: Number
}

我需要计算所有付款的总和除以所有用户的数量。

在此之后,我需要将它们按OS分组,即拥有os='os1'的用户支付的所有款项之和除以每个操作系统拥有os='os1'的所有用户的数量。

编辑

例如,用户的示例数据是:

代码语言:javascript
复制
{
    "_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"
}

支付的样本数据如下:

代码语言:javascript
复制
{
    "_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

  • 请注意,一些用户可能不会支付任何费用,但他们需要计算ARPU。
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-12-26 13:41:46

您可以从$lookup开始,然后使用$reduce计算每个用户的totalPayments。然后您可以通过$group by null获得包含用户总数和总付款的单个文档。要获得ARPU,最后一步需要$divide

代码语言:javascript
复制
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

代码语言:javascript
复制
{
    $group: {
        _id: "$os",
        totalUsers: { $sum: 1 },
        totalPayments: { $sum: "$totalPayments" }
    }
}

指纹:

代码语言:javascript
复制
{ "_id" : "ios", "arpu" : 10 }
{ "_id" : "android", "arpu" : 6.666666666666667 }
票数 2
EN

Stack Overflow用户

发布于 2018-12-26 14:30:44

利用$facet的使用,在$lookup阶段之后在一个管道中获得这两组计算。

下面演示如何将$facet用于上述聚合操作:

代码语言:javascript
复制
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" }
            } }
        ]
    } }
])

这将为给定的示例文档产生如下结果:

代码语言:javascript
复制
{
    "users" : [ 
        {
            "_id" : null,
            "ARPU" : 8.0
        }
    ],
    "os" : [ 
        {
            "ios-ARPU" : 10.0,
            "android-ARPU" : 6.66666666666667
        }
    ]
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53929618

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档