From 414383163e2a7ca1851e20f1af3799b276ad6b3e Mon Sep 17 00:00:00 2001 From: Primakov Alexandr Alexandrovich Date: Mon, 17 Nov 2025 14:40:37 +0300 Subject: [PATCH] Enhance smoke-tracker API to include statistics for active users only; update documentation to reflect changes in user activity criteria and statistics calculations. --- server/routers/smoke-tracker/API.md | 16 +++++---- server/routers/smoke-tracker/stats.js | 50 +++++++++++++++++++++++---- 2 files changed, 54 insertions(+), 12 deletions(-) diff --git a/server/routers/smoke-tracker/API.md b/server/routers/smoke-tracker/API.md index f4ab7ba..4d810dd 100644 --- a/server/routers/smoke-tracker/API.md +++ b/server/routers/smoke-tracker/API.md @@ -508,13 +508,17 @@ curl -X GET http://localhost:8044/smoke-tracker/stats/summary \ - `total` — общее количество сигарет за период - `daysWithData` — количество дней, в которые были записи -**`global`** — общая статистика по всем пользователям: -- `daily` — массив с суммарным количеством сигарет всех пользователей по дням -- `averagePerDay` — среднее количество сигарет в день (все пользователи) -- `weekday` — статистика по дням недели (все пользователи) -- `total` — общее количество сигарет всех пользователей за период +**`global`** — общая статистика по всем **активным** пользователям: +- `daily` — массив с суммарным количеством сигарет всех активных пользователей по дням +- `averagePerDay` — среднее количество сигарет в день (активные пользователи) +- `weekday` — статистика по дням недели (активные пользователи) +- `total` — общее количество сигарет всех активных пользователей за период - `daysWithData` — количество дней с записями -- `activeUsers` — количество уникальных пользователей, записывавших сигареты в период +- `activeUsers` — количество активных пользователей в период + +> **Примечание**: Активными считаются только пользователи, которые в среднем выкуривают **от 2 до 40 сигарет в день**. Это позволяет исключить из статистики: +> - Тестовые аккаунты и неактивных пользователей (< 2 сигарет/день) +> - Ошибочные или накликанные данные (> 40 сигарет/день) **`period`** — информация о запрошенном периоде: - `from` — начало периода (ISO 8601) diff --git a/server/routers/smoke-tracker/stats.js b/server/routers/smoke-tracker/stats.js index 3e960e0..2d135b7 100644 --- a/server/routers/smoke-tracker/stats.js +++ b/server/routers/smoke-tracker/stats.js @@ -150,9 +150,47 @@ router.get('/summary', async (req, res, next) => { } }) - // 4. Общая статистика по всем пользователям - const globalDailyStats = await CigaretteModel.aggregate([ + // 4. Определяем активных пользователей (от 2 до 40 сигарет в день в среднем) + const MIN_CIGARETTES_PER_DAY = 2 + const MAX_CIGARETTES_PER_DAY = 40 + const periodDays = Math.ceil((toDate.getTime() - fromDate.getTime()) / (1000 * 60 * 60 * 24)) + + // Получаем статистику по каждому пользователю + const userStats = await CigaretteModel.aggregate([ { $match: globalMatch }, + { + $group: { + _id: '$userId', + total: { $sum: 1 }, + }, + }, + ]) + + // Фильтруем активных пользователей (исключаем слишком низкие и слишком высокие значения) + const activeUserIds = userStats + .filter((stat) => { + const avgPerDay = stat.total / periodDays + return avgPerDay > MIN_CIGARETTES_PER_DAY && avgPerDay <= MAX_CIGARETTES_PER_DAY + }) + .map((stat) => stat._id) + + const filteredLow = userStats.filter((stat) => stat.total / periodDays <= MIN_CIGARETTES_PER_DAY).length + const filteredHigh = userStats.filter((stat) => stat.total / periodDays > MAX_CIGARETTES_PER_DAY).length + + console.log('[STATS] Total users:', userStats.length) + console.log('[STATS] Active users (2-40 cigs/day):', activeUserIds.length) + console.log('[STATS] Filtered out (too low):', filteredLow) + console.log('[STATS] Filtered out (too high):', filteredHigh) + + // Фильтр только для активных пользователей + const activeGlobalMatch = { + ...globalMatch, + userId: { $in: activeUserIds }, + } + + // Общая статистика по активным пользователям + const globalDailyStats = await CigaretteModel.aggregate([ + { $match: activeGlobalMatch }, { $group: { _id: { @@ -174,9 +212,9 @@ router.get('/summary', async (req, res, next) => { const globalAveragePerDay = globalDaysWithData > 0 ? (globalTotalCigarettes / globalDaysWithData).toFixed(2) : 0 - // Общая статистика по дням недели (все пользователи) + // Общая статистика по дням недели (активные пользователи) const globalWeekdayStats = await CigaretteModel.aggregate([ - { $match: globalMatch }, + { $match: activeGlobalMatch }, { $group: { _id: { $dayOfWeek: '$smokedAt' }, @@ -205,8 +243,8 @@ router.get('/summary', async (req, res, next) => { } }) - // Количество активных пользователей в периоде - const activeUsers = await CigaretteModel.distinct('userId', globalMatch) + // Количество активных пользователей + const activeUsers = activeUserIds const result = { user: {