Удержание в первую неделю с MongoDB - PullRequest
1 голос
/ 26 мая 2020

Одна таблица с событиями начала сеанса:

start data sheet

Зарегистрировано - unixtime - когда пользователь был зарегистрирован (впервые открыл приложение)

DateTime - unixtime - время отправки события (когда игрок устанавливает приложение и открывает его в первый раз: Registered = DateTime)

PlayerId - уникальный идентификатор для игрока (тот же идентификатор - всегда тот же Зарегистрированный, но такой же зарегистрированный - может быть больше одного PlayerId для этого)

Мне нужно получить такую ​​таблицу:

Nice-looking Retention sheet

Сделал этот запрос (MongoDB для reda sh) до сих пор:

{
    "collection": "dance",
    "aggregate": [
        {
            "$match": {
                "$and": [
                    {
//---filter for the range of Day0 dates
//---need to build Ret_Day1 - Ret_Day7 for each
                        "Registered": {
                            "$lt": "ISODate(\"{{Finish date}}\")"
                        }
                    },
                    {
                        "Registered": {
                            "$gt": "ISODate(\"{{Start date}}\")"
                        }
                    },
                    {
                        "EventType": "Session Start"
                    }
                ]
            }
        },
        {
            "$group": {
                "_id": {
                    "DayZero": {
                        "$dateToString": {
                            "format": "%Y-%m-%d",
                            "date": "$Registered"
                        }
                    },
                    "DayActive": {
                        "$dateToString": {
                            "format": "%Y-%m-%d",
                            "date": "$DateTime"
                        }
                    },
                    "PlayerId": "$PlayerId"
                }
            }
        },
        {
            "$group": {
                "_id": {
                    "DayZero": "$_id.DayZero",
                    "DayActive": "$_id.DayActive"
                },
                "Ret": {
                    "$sum": 1
                }
            }
        },
        {
            "$project": {
                "_id": "1",
                "DayZero": {
                    "$dateFromString": {
                        "dateString": "$_id.DayZero"
                    }
                },
                "DayActive": {
                    "$dateFromString": {
                        "dateString": "$_id.DayActive"
                    }
                },
                "Ret": 1
            }
        },
        {
            "$project": {
                "Days": {
                    "$divide": [
                        {
                            "$subtract": [
                                "$DayActive",
                                "$DayZero"
                            ]
                        },
                        86400000
                    ]
                },
                "DayZero": {
                    "$dateToParts": {
                        "date": "$DayZero",
                        "timezone": "+02:00"
                    }
                },
                "Ret": 1
            }
        },
        {
            "$project": {
                "Ret": 1,
                "Days": 1,
                "DayZero": {
                    "$concat": [
                        {
                            "$toString": "$DayZero.day"
                        },
                        ".",
                        {
                            "$toString": "$DayZero.month"
                        },
                        ".",
                        {
                            "$toString": "$DayZero.year"
                        }
                    ]
                }
            }
        }
    ]
}

Результат:

raw data

В реда sh я могу построить такую ​​визуализацию:

pivot table

Но этого недостаточно - поэтому я хочу заполнить новые поля (R_Day1 - R_Day7 ) с количеством пользователей и процентом пользователей. Какой метод будет проще всего для расчета процентов на каждый день?

1 Ответ

0 голосов
/ 27 мая 2020
• 1000 1003 *
{
    "day": string
    "newUsers" : number,
    "DateTimes" : Array<{day: number, month: number, year: number, users: number, percentage: number}> 
}

С уже отсортированным массивом DateTime, поэтому для R_1 вы должны использовать DateTime[0].percentage для процента пользователей на этот день.

db.collection.aggregate([
    {
        $group: {
            _id: {
                day: {$dayOfMonth: "$Registered"},
                month: {$month: "$Registered"},
                year: {$year: "$Registered"},
                dateTimeDay: {$dayOfMonth: "$DateTime"},
                dateTimeMonth: {$month: "$DateTime"},
                dateTimeYear: {$year: "$DateTime"}
            },
            users: {$addToSet: "$PlayerId"}
        }
    },
    {
        $group: {
            _id: {day: "$_id.day", month: "$_id.month", year: "$_id.year"},
            totalUsers: {$addToSet: "$users"},
            DateTimes: {
                $push: {
                    day: "$_id.dateTimeDay",
                    month: "$_id.dateTimeMonth",
                    year: "$_id.dateTimeYear",
                    users: {$size: "$users"}
                }
            }
        }
    },
    {
        $addFields: {
            R1_to_R7: {
                $map: {
                    input: [1, 2, 3, 4, 5, 6, 7],
                    as: "input",
                    in: {
                        $cond: [
                            {$setIsSubset: [["$_id.month"], [1, 3, 5, 7, 8, 10, 12]]},
                            {
                                $cond: [
                                    {
                                        $and: [
                                            {$lt: [{$mod: [{$sum: ["$_id.day", "$$input"]}, 32]}, 7]},
                                            {$gt: ["$_id.day", 20]}
                                        ]
                                    },
                                    {
                                        day: {$sum: [{$mod: [{$sum: ["$_id.day", "$$input"]}, 32]}, 1]},
                                        month: {
                                            $cond: [
                                                {$eq: [{$mod: [{$sum: ["$_id.month", 1]}, 13]}, 0]},
                                                1,
                                                {$sum: ["$_id.month", 1]},
                                            ]
                                        },
                                        year: {
                                            $cond: [
                                                {$eq: [{$mod: [{$sum: ["$_id.month", 1]}, 13]}, 0]},
                                                {$sum: ["$_id.year", 1]},
                                                "$_id.year"
                                            ]
                                        }
                                    },
                                    {
                                        day: {$mod: [{$sum: ["$_id.day", "$$input"]}, 32]},
                                        month: "$_id.month",
                                        year: "$_id.year"
                                    }
                                ]
                            },
                            {
                                $cond: [
                                    {
                                        $eq: ["$_id.month", 2]
                                    },
                                    {
                                        $cond: [
                                            {
                                                $and: [
                                                    {$lt: [{$mod: [{$sum: ["$_id.day", "$$input"]}, 29]}, 7]},
                                                    {$gt: ["$_id.day", 20]}
                                                ]
                                            },
                                            {
                                                day: {$sum: [{$mod: [{$sum: ["$_id.day", "$$input"]}, 29]}, 1]},
                                                month: 3,
                                                year: "$_id.year",
                                            },
                                            {
                                                day: {$mod: [{$sum: ["$_id.day", "$$input"]}, 29]},
                                                month: "$_id.month",
                                                year: "$_id.year"
                                            }
                                        ]
                                    },
                                    {
                                        $cond: [
                                            {
                                                $and: [
                                                    {$lt: [{$mod: [{$sum: ["$_id.day", "$$input"]}, 31]}, 7]},
                                                    {$gt: ["$_id.day", 20]}
                                                ]
                                            },
                                            {
                                                day: {$sum: [{$mod: [{$sum: ["$_id.day", "$$input"]}, 31]}, 1]},
                                                month: {$sum: ["$_id.month", 1]},
                                                year: "$_id.year",
                                            },
                                            {
                                                day: {$mod: [{$sum: ["$_id.day", "$$input"]}, 31]},
                                                month: "$_id,month",
                                                year: "$_id.year"
                                            }
                                        ]
                                    }
                                ]
                            }
                        ]
                    }
                }
            }
        }
    },
    {
        $project: {
            _id: 0,
             day: {$concat: [{$toString: "$_id.day"}, "/", {$toString: "$_id.month"}, "/", {$toString: "$_id.year"}]},
            newUsers: {
                $size: {
                    $reduce: {
                        input: "$totalUsers",
                        initialValue: [],
                        in: {$setUnion: ["$$value", "$$this"]}
                    }
                }
            },
            DateTimes: {
                $map: {
                    input: "$R1_to_R7",
                    as: "next_day",
                    in: {
                        $cond: [
                            {
                                $gt: [
                                    {
                                        $size: {
                                            $filter: {
                                                input: "$DateTimes",
                                                as: "dateTime",
                                                cond: {
                                                    $eq: [{
                                                        day: "$$dateTime.day",
                                                        month: "$$dateTime.month",
                                                        year: "$$dateTime.year"
                                                    }, "$$next_day"]
                                                }
                                            }
                                        }
                                    },
                                    0
                                ]
                            },
                            {
                                $arrayElemAt: [
                                    {

                                        $filter: {
                                            input: "$DateTimes",
                                            as: "dateTime",
                                            cond: {
                                                $eq: [{
                                                    day: "$$dateTime.day",
                                                    month: "$$dateTime.month",
                                                    year: "$$dateTime.year"
                                                }, "$$next_day"]
                                            }
                                        }
                                    },
                                    0
                                ]
                            },
                            {
                                $mergeObjects: ["$$next_day", {users: 0}]
                            }
                        ]
                    }
                }
            }
        }
    },
    {
        $project: {
            day: 1,
            newUsers: 1,
            DateTimes: {
                $map: {
                    input: "$DateTimes",
                    as: "datetime",
                    in: {
                        $mergeObjects: [
                            "$$datetime",
                            {percentage: {$multiply: [100, {$divide: ["$$datetime.users", "$newUsers"]}]}}
                        ]
                    }
                }
            }
        }
    }
])

С этим вне способ Еще 2 вещи, которые следует учитывать:

  1. Первый этап $addFields используется для «добавления» следующих 7 дней. это довольно сложно сделать Mon go в данном контексте. если бы вы могли сделать это в коде, было бы лучше, поскольку существует много дублирования.
  2. Как видите, мне пришлось изменить значения day, month и year на следующие 7 дней, если регистрация была, скажем, 31-го числа. НО я не учел разрыв в годах. если вы хотите сохранить его таким образом и чтобы он был стабильным, вы должны добавить проверку промежуточного года ($mod должен работать нормально, так как это каждые 4 года.) к условию с 2 месяцем (февраль).
...