首页 > 解决方案 > MongoDB聚合查询计算用户和支付模型分离时的ARPU

问题描述

我想编写一个聚合查询来计算 ARPU(每个用户的平均收入),但我被困在如何使用来自不同模型的数据,我知道我可以加入模型,$lookup但我无法计算所有用户的数量方法。

这些是我的模型:

// User:
{
    _id,
    username: String,
    os: String
}

// Payment:
{
    _id,
    user: ObjectId,
    price: Number
}

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

之后,我需要按操作系统对它们进行分组,即用户支付的所有款项的总和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
}

我的预期输出是使用聚合查询实现的数字。

最初我想要的是每位用户的平均收入:

每用户平均收入: {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

安卓ARPU: {sum of payments android users made} / {count of android usrs} = 20 / 3 = 6.67

标签: mongodbaggregation-frameworkaverage

解决方案


您可以从$lookup开始,然后使用$reduce计算totalPayments每个用户。然后您可以$group bynull以获取包含用户总数和总付款的单个文档。要获得 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 }

推荐阅读