diff --git a/README.md b/README.md
index d0a0b7ee..7b8bbb33 100644
--- a/README.md
+++ b/README.md
@@ -38,7 +38,7 @@ As of today (2023-12-12) I have more then 1.2 million events in PSQL and perform
- [ ] Area
- [ ] Support funnels
- [ ] Support multiple breakdowns
-- [ ] Aggregations (sum, average...)
+- [x] Aggregations (sum, average...)
### SDK
diff --git a/apps/web/src/components/report/sidebar/ReportEvents.tsx b/apps/web/src/components/report/sidebar/ReportEvents.tsx
index 5dea0574..87302819 100644
--- a/apps/web/src/components/report/sidebar/ReportEvents.tsx
+++ b/apps/web/src/components/report/sidebar/ReportEvents.tsx
@@ -87,6 +87,10 @@ export function ReportEvents() {
value: 'user',
label: 'Unique users',
},
+ {
+ value: 'user_average',
+ label: 'Unique users (average)',
+ },
]}
label="Segment"
>
@@ -95,6 +99,10 @@ export function ReportEvents() {
<>
Unique users
>
+ ) : event.segment === 'user_average' ? (
+ <>
+ Average per user
+ >
) : (
<>
All events
diff --git a/apps/web/src/server/api/routers/chart.ts b/apps/web/src/server/api/routers/chart.ts
index e157ec83..c1265691 100644
--- a/apps/web/src/server/api/routers/chart.ts
+++ b/apps/web/src/server/api/routers/chart.ts
@@ -236,20 +236,24 @@ function getDatesFromRange(range: IChartRange) {
}
if (isFloat(range)) {
- const startDate = new Date(Date.now() - 1000 * 60 * (range * 100));
+ const startDate = new Date(
+ Date.now() - 1000 * 60 * (range * 100)
+ ).toISOString();
const endDate = new Date().toISOString();
return {
- startDate: startDate.toISOString(),
- endDate: endDate,
+ startDate,
+ endDate,
};
}
- const startDate = getDaysOldDate(range).toISOString();
- const endDate = new Date().toISOString();
+ const startDate = getDaysOldDate(range);
+ startDate.setUTCHours(0, 0, 0, 0);
+ const endDate = new Date();
+ endDate.setUTCHours(23, 59, 59, 999);
return {
- startDate,
- endDate,
+ startDate: startDate.toISOString(),
+ endDate: endDate.toISOString(),
};
}
@@ -271,6 +275,8 @@ function getChartSql({
if (event.segment === 'event') {
select.push(`count(*)::int as count`);
+ } else if (event.segment === 'user_average') {
+ select.push(`COUNT(*)::float / COUNT(DISTINCT profile_id)::float as count`);
} else {
select.push(`count(DISTINCT profile_id)::int as count`);
}
@@ -396,6 +402,8 @@ function getChartSql({
sql.push(`ORDER BY ${orderBy.join(', ')}`);
}
+ console.log('SQL ->', sql.join('\n'));
+
return sql.join('\n');
}
diff --git a/apps/web/src/utils/validation.ts b/apps/web/src/utils/validation.ts
index fed48ef1..0e5d3962 100644
--- a/apps/web/src/utils/validation.ts
+++ b/apps/web/src/utils/validation.ts
@@ -10,7 +10,7 @@ function objectToZodEnums(obj: Record): [K, ...K[]] {
export const zChartEvent = z.object({
id: z.string(),
name: z.string(),
- segment: z.enum(['event', 'user']),
+ segment: z.enum(['event', 'user', 'user_average']),
filters: z.array(
z.object({
id: z.string(),