Skip to content

Commit 189b218

Browse files
authored
[front] - fix(analytics): workspace analytics computation (#11515)
* [front/pages/api/w/[wId]] - refactor: optimize active user analytics query - Simplified and optimized the query for calculating active user counts and growth percentages - Replaced multiple common table expressions with a more efficient single CTE approach - Removed unnecessary group by and having clauses to streamline the query execution - Improved performance by reducing the complexity of conditional counting within the query * [api] - fix: correct workspace analytics query parameters and growth percentage calculation - Replace hardcoded workspace identifier with dynamic parameter binding in SQL query for analytics - Multiply month-over-month and week-over-week growth percentages by 100 for accurate representation
1 parent 0295c65 commit 189b218

File tree

1 file changed

+75
-45
lines changed

1 file changed

+75
-45
lines changed

front/pages/api/w/[wId]/workspace-analytics.ts

Lines changed: 75 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -97,53 +97,83 @@ async function getAnalytics(
9797
}
9898
),
9999
replicaDb.query<ActiveUsersQueryResult>(
100-
`WITH activity_periods AS (
101-
SELECT
102-
"user_messages"."userId",
103-
COUNT(*) AS message_count,
104-
CASE
105-
WHEN "user_messages"."createdAt" >= CURRENT_DATE - INTERVAL '7 days' THEN 'last_7_days'
106-
WHEN "user_messages"."createdAt" < CURRENT_DATE - INTERVAL '7 days' AND "user_messages"."createdAt" >= CURRENT_DATE - INTERVAL '14 days' THEN 'previous_7_days'
107-
WHEN "user_messages"."createdAt" >= CURRENT_DATE - INTERVAL '30 days' THEN 'last_30_days'
108-
WHEN "user_messages"."createdAt" < CURRENT_DATE - INTERVAL '30 days' AND "user_messages"."createdAt" >= CURRENT_DATE - INTERVAL '60 days' THEN 'previous_30_days'
109-
END AS period
110-
FROM "user_messages"
111-
JOIN "messages" ON "messages"."userMessageId" = "user_messages"."id"
112-
JOIN "conversations" ON "messages"."conversationId" = "conversations"."id"
113-
JOIN "workspaces" ON "conversations"."workspaceId" = "workspaces"."id"
114-
WHERE "workspaces"."sId" = :wId
115-
AND "user_messages"."createdAt" >= CURRENT_DATE - INTERVAL '60 days'
116-
GROUP BY "user_messages"."userId", period
117-
HAVING COUNT(*) >= :messageCountThreshold
118-
),
119-
aggregated_counts AS (
120-
SELECT
121-
period,
122-
COUNT("userId") AS active_users
123-
FROM activity_periods
124-
GROUP BY period
125-
),
126-
growth_calculations AS (
100+
`
101+
WITH
102+
raw_counts AS (
103+
SELECT
104+
COUNT(
105+
DISTINCT (
106+
CASE
107+
WHEN "user_messages"."createdAt" >= CURRENT_DATE - INTERVAL '7 days' THEN "userId"
108+
ELSE NULL
109+
END
110+
)
111+
) AS "nb_active_users_last_7_days",
112+
COUNT(
113+
DISTINCT (
114+
CASE
115+
WHEN "user_messages"."createdAt" < CURRENT_DATE - INTERVAL '7 days'
116+
AND "user_messages"."createdAt" >= CURRENT_DATE - INTERVAL '14 days' THEN "userId"
117+
ELSE NULL
118+
END
119+
)
120+
) AS "nb_active_users_previous_7_days",
121+
COUNT(
122+
DISTINCT (
123+
CASE
124+
WHEN "user_messages"."createdAt" >= CURRENT_DATE - INTERVAL '30 days' THEN "userId"
125+
ELSE NULL
126+
END
127+
)
128+
) AS "nb_active_users_last_30_days",
129+
COUNT(
130+
DISTINCT (
131+
CASE
132+
WHEN "user_messages"."createdAt" < CURRENT_DATE - INTERVAL '30 days'
133+
AND "user_messages"."createdAt" >= CURRENT_DATE - INTERVAL '60 days' THEN "userId"
134+
ELSE NULL
135+
END
136+
)
137+
) AS "nb_active_users_previous_30_days"
138+
FROM
139+
"user_messages"
140+
JOIN "messages" ON "messages"."userMessageId" = "user_messages"."id"
141+
JOIN "conversations" ON "messages"."conversationId" = "conversations"."id"
142+
JOIN "workspaces" ON "conversations"."workspaceId" = "workspaces"."id"
143+
WHERE
144+
"workspaces"."sId" = :wId
145+
AND "user_messages"."createdAt" >= CURRENT_DATE - INTERVAL '60 days'
146+
),
147+
calculations AS (
148+
SELECT
149+
"nb_active_users_last_7_days",
150+
CASE
151+
WHEN "nb_active_users_previous_7_days" = 0 THEN NULL
152+
ELSE (
153+
"nb_active_users_last_7_days"::float - "nb_active_users_previous_7_days"::float
154+
) / "nb_active_users_previous_7_days"::float
155+
END AS "wow_growth_pct",
156+
"nb_active_users_last_30_days",
157+
CASE
158+
WHEN "nb_active_users_previous_30_days" = 0 THEN NULL
159+
ELSE (
160+
"nb_active_users_last_30_days"::float - "nb_active_users_previous_30_days"::float
161+
) / "nb_active_users_previous_30_days"::float
162+
END AS "mom_growth_pct"
163+
FROM
164+
raw_counts
165+
)
127166
SELECT
128-
COALESCE(MAX(CASE WHEN period = 'last_7_days' THEN active_users END), 0) AS "last_7_days_active_users",
129-
COALESCE(MAX(CASE WHEN period IN ('last_30_days', 'last_7_days', 'previous_7_days') THEN active_users END), 0) AS "last_30_days_active_users",
130-
(COALESCE(MAX(CASE WHEN period = 'last_7_days' THEN active_users END), 0) - COALESCE(MAX(CASE WHEN period = 'previous_7_days' THEN active_users END), 0))::FLOAT
131-
/ GREATEST(COALESCE(MAX(CASE WHEN period = 'previous_7_days' THEN active_users END), 1), 1) * 100 AS "wow_growth_pct",
132-
(COALESCE(MAX(CASE WHEN period IN ('last_30_days', 'last_7_days', 'previous_7_days') THEN active_users END), 0) - COALESCE(MAX(CASE WHEN period = 'previous_30_days' THEN active_users END), 0))::FLOAT
133-
/ GREATEST(COALESCE(MAX(CASE WHEN period = 'previous_30_days' THEN active_users END), 1), 1) * 100 AS "mom_growth_pct"
134-
FROM aggregated_counts
135-
)
136-
SELECT
137-
"last_7_days_active_users",
138-
ROUND(wow_growth_pct::Decimal, 2) AS "wow_growth_pct",
139-
"last_30_days_active_users",
140-
ROUND(mom_growth_pct::Decimal, 2) AS "mom_growth_pct"
141-
FROM growth_calculations;
142-
`,
167+
"nb_active_users_last_7_days",
168+
"wow_growth_pct",
169+
"nb_active_users_last_30_days",
170+
"mom_growth_pct"
171+
FROM
172+
calculations;
173+
`,
143174
{
144175
replacements: {
145176
wId,
146-
messageCountThreshold: 1,
147177
},
148178
type: QueryTypes.SELECT,
149179
}
@@ -210,11 +240,11 @@ async function getAnalytics(
210240
memberCount: memberCountResults[0].member_count,
211241
monthlyActiveUsers: {
212242
count: activeUsersResult[0].last_30_days_active_users,
213-
growth: activeUsersResult[0].mom_growth_pct,
243+
growth: activeUsersResult[0].mom_growth_pct * 100,
214244
},
215245
weeklyActiveUsers: {
216246
count: activeUsersResult[0].last_7_days_active_users,
217-
growth: activeUsersResult[0].wow_growth_pct,
247+
growth: activeUsersResult[0].wow_growth_pct * 100,
218248
},
219249
averageWeeklyDailyActiveUsers: {
220250
count: averageWeeklyDauResult[0].last_7_days_average_daily_active_users,

0 commit comments

Comments
 (0)