Merge branch 'dev' into jajaja

# Conflicts:
#	pnpm-lock.yaml
#	src/app/(main)/websites/[websiteId]/events/EventProperties.tsx
#	src/components/messages.ts
#	src/lib/constants.ts
#	src/queries/sql/pageviews/getPageviewMetrics.ts
#	src/queries/sql/sessions/getWebsiteSessions.ts
This commit is contained in:
Mike Cao 2025-07-15 13:01:50 -07:00
commit a9a9b57f80
10 changed files with 356 additions and 90 deletions

View file

@ -0,0 +1,253 @@
-- create new hourly table
CREATE TABLE umami.website_event_stats_hourly_new
(
website_id UUID,
session_id UUID,
visit_id UUID,
hostname SimpleAggregateFunction(groupArrayArray, Array(String)),
browser LowCardinality(String),
os LowCardinality(String),
device LowCardinality(String),
screen LowCardinality(String),
language LowCardinality(String),
country LowCardinality(String),
region LowCardinality(String),
city String,
entry_url AggregateFunction(argMin, String, DateTime('UTC')),
exit_url AggregateFunction(argMax, String, DateTime('UTC')),
url_path SimpleAggregateFunction(groupArrayArray, Array(String)),
url_query SimpleAggregateFunction(groupArrayArray, Array(String)),
utm_source SimpleAggregateFunction(groupArrayArray, Array(String)),
utm_medium SimpleAggregateFunction(groupArrayArray, Array(String)),
utm_campaign SimpleAggregateFunction(groupArrayArray, Array(String)),
utm_content SimpleAggregateFunction(groupArrayArray, Array(String)),
utm_term SimpleAggregateFunction(groupArrayArray, Array(String)),
referrer_domain SimpleAggregateFunction(groupArrayArray, Array(String)),
page_title SimpleAggregateFunction(groupArrayArray, Array(String)),
gclid SimpleAggregateFunction(groupArrayArray, Array(String)),
fbclid SimpleAggregateFunction(groupArrayArray, Array(String)),
msclkid SimpleAggregateFunction(groupArrayArray, Array(String)),
ttclid SimpleAggregateFunction(groupArrayArray, Array(String)),
li_fat_id SimpleAggregateFunction(groupArrayArray, Array(String)),
twclid SimpleAggregateFunction(groupArrayArray, Array(String)),
event_type UInt32,
event_name SimpleAggregateFunction(groupArrayArray, Array(String)),
views SimpleAggregateFunction(sum, UInt64),
min_time SimpleAggregateFunction(min, DateTime('UTC')),
max_time SimpleAggregateFunction(max, DateTime('UTC')),
tag SimpleAggregateFunction(groupArrayArray, Array(String)),
distinct_id String,
created_at Datetime('UTC')
)
ENGINE = AggregatingMergeTree
PARTITION BY toYYYYMM(created_at)
ORDER BY (
website_id,
event_type,
toStartOfHour(created_at),
cityHash64(visit_id),
visit_id
)
SAMPLE BY cityHash64(visit_id);
-- create view
CREATE MATERIALIZED VIEW umami.website_event_stats_hourly_mv_new
TO umami.website_event_stats_hourly_new
AS
SELECT
website_id,
session_id,
visit_id,
hostnames as hostname,
browser,
os,
device,
screen,
language,
country,
region,
city,
entry_url,
exit_url,
url_paths as url_path,
url_query,
utm_source,
utm_medium,
utm_campaign,
utm_content,
utm_term,
referrer_domain,
page_title,
gclid,
fbclid,
msclkid,
ttclid,
li_fat_id,
twclid,
event_type,
event_name,
views,
min_time,
max_time,
tag,
distinct_id,
timestamp as created_at
FROM (SELECT
website_id,
session_id,
visit_id,
arrayFilter(x -> x != '', groupArray(hostname)) hostnames,
browser,
os,
device,
screen,
language,
country,
region,
city,
argMinState(url_path, created_at) entry_url,
argMaxState(url_path, created_at) exit_url,
arrayFilter(x -> x != '', groupArray(url_path)) as url_paths,
arrayFilter(x -> x != '', groupArray(url_query)) url_query,
arrayFilter(x -> x != '', groupArray(utm_source)) utm_source,
arrayFilter(x -> x != '', groupArray(utm_medium)) utm_medium,
arrayFilter(x -> x != '', groupArray(utm_campaign)) utm_campaign,
arrayFilter(x -> x != '', groupArray(utm_content)) utm_content,
arrayFilter(x -> x != '', groupArray(utm_term)) utm_term,
arrayFilter(x -> x != '' and x != hostname, groupArray(referrer_domain)) referrer_domain,
arrayFilter(x -> x != '', groupArray(page_title)) page_title,
arrayFilter(x -> x != '', groupArray(gclid)) gclid,
arrayFilter(x -> x != '', groupArray(fbclid)) fbclid,
arrayFilter(x -> x != '', groupArray(msclkid)) msclkid,
arrayFilter(x -> x != '', groupArray(ttclid)) ttclid,
arrayFilter(x -> x != '', groupArray(li_fat_id)) li_fat_id,
arrayFilter(x -> x != '', groupArray(twclid)) twclid,
event_type,
if(event_type = 2, groupArray(event_name), []) event_name,
sumIf(1, event_type = 1) views,
min(created_at) min_time,
max(created_at) max_time,
arrayFilter(x -> x != '', groupArray(tag)) tag,
distinct_id,
toStartOfHour(created_at) timestamp
FROM umami.website_event
GROUP BY website_id,
session_id,
visit_id,
hostname,
browser,
os,
device,
screen,
language,
country,
region,
city,
event_type,
distinct_id,
timestamp);
-- rename tables
RENAME TABLE umami.website_event_stats_hourly TO umami.website_event_stats_hourly_old;
RENAME TABLE umami.website_event_stats_hourly_new TO umami.website_event_stats_hourly;
-- drop views
DROP TABLE umami.website_event_stats_hourly_mv;
DROP TABLE umami.website_event_stats_hourly_mv_new;
-- recreate view
CREATE MATERIALIZED VIEW umami.website_event_stats_hourly_mv
TO umami.website_event_stats_hourly
AS
SELECT
website_id,
session_id,
visit_id,
hostnames as hostname,
browser,
os,
device,
screen,
language,
country,
region,
city,
entry_url,
exit_url,
url_paths as url_path,
url_query,
utm_source,
utm_medium,
utm_campaign,
utm_content,
utm_term,
referrer_domain,
page_title,
gclid,
fbclid,
msclkid,
ttclid,
li_fat_id,
twclid,
event_type,
event_name,
views,
min_time,
max_time,
tag,
distinct_id,
timestamp as created_at
FROM (SELECT
website_id,
session_id,
visit_id,
arrayFilter(x -> x != '', groupArray(hostname)) hostnames,
browser,
os,
device,
screen,
language,
country,
region,
city,
argMinState(url_path, created_at) entry_url,
argMaxState(url_path, created_at) exit_url,
arrayFilter(x -> x != '', groupArray(url_path)) as url_paths,
arrayFilter(x -> x != '', groupArray(url_query)) url_query,
arrayFilter(x -> x != '', groupArray(utm_source)) utm_source,
arrayFilter(x -> x != '', groupArray(utm_medium)) utm_medium,
arrayFilter(x -> x != '', groupArray(utm_campaign)) utm_campaign,
arrayFilter(x -> x != '', groupArray(utm_content)) utm_content,
arrayFilter(x -> x != '', groupArray(utm_term)) utm_term,
arrayFilter(x -> x != '' and x != hostname, groupArray(referrer_domain)) referrer_domain,
arrayFilter(x -> x != '', groupArray(page_title)) page_title,
arrayFilter(x -> x != '', groupArray(gclid)) gclid,
arrayFilter(x -> x != '', groupArray(fbclid)) fbclid,
arrayFilter(x -> x != '', groupArray(msclkid)) msclkid,
arrayFilter(x -> x != '', groupArray(ttclid)) ttclid,
arrayFilter(x -> x != '', groupArray(li_fat_id)) li_fat_id,
arrayFilter(x -> x != '', groupArray(twclid)) twclid,
event_type,
if(event_type = 2, groupArray(event_name), []) event_name,
sumIf(1, event_type = 1) views,
min(created_at) min_time,
max(created_at) max_time,
arrayFilter(x -> x != '', groupArray(tag)) tag,
distinct_id,
toStartOfHour(created_at) timestamp
FROM umami.website_event
GROUP BY website_id,
session_id,
visit_id,
hostname,
browser,
os,
device,
screen,
language,
country,
region,
city,
event_type,
distinct_id,
timestamp);

View file

@ -90,7 +90,7 @@ CREATE TABLE umami.website_event_stats_hourly
website_id UUID, website_id UUID,
session_id UUID, session_id UUID,
visit_id UUID, visit_id UUID,
hostname LowCardinality(String), hostname SimpleAggregateFunction(groupArrayArray, Array(String)),
browser LowCardinality(String), browser LowCardinality(String),
os LowCardinality(String), os LowCardinality(String),
device LowCardinality(String), device LowCardinality(String),
@ -143,7 +143,7 @@ SELECT
website_id, website_id,
session_id, session_id,
visit_id, visit_id,
hostname, hostnames as hostname,
browser, browser,
os, os,
device, device,
@ -181,7 +181,7 @@ FROM (SELECT
website_id, website_id,
session_id, session_id,
visit_id, visit_id,
hostname, arrayFilter(x -> x != '', groupArray(hostname)) hostnames,
browser, browser,
os, os,
device, device,
@ -199,7 +199,7 @@ FROM (SELECT
arrayFilter(x -> x != '', groupArray(utm_campaign)) utm_campaign, arrayFilter(x -> x != '', groupArray(utm_campaign)) utm_campaign,
arrayFilter(x -> x != '', groupArray(utm_content)) utm_content, arrayFilter(x -> x != '', groupArray(utm_content)) utm_content,
arrayFilter(x -> x != '', groupArray(utm_term)) utm_term, arrayFilter(x -> x != '', groupArray(utm_term)) utm_term,
arrayFilter(x -> x != '', groupArray(referrer_domain)) referrer_domain, arrayFilter(x -> x != '' and x != hostname, groupArray(referrer_domain)) referrer_domain,
arrayFilter(x -> x != '', groupArray(page_title)) page_title, arrayFilter(x -> x != '', groupArray(page_title)) page_title,
arrayFilter(x -> x != '', groupArray(gclid)) gclid, arrayFilter(x -> x != '', groupArray(gclid)) gclid,
arrayFilter(x -> x != '', groupArray(fbclid)) fbclid, arrayFilter(x -> x != '', groupArray(fbclid)) fbclid,

View file

@ -1,25 +0,0 @@
.container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(420px, 1fr));
gap: 60px;
margin-bottom: 40px;
}
.table {
align-self: flex-start;
}
.link:hover {
cursor: pointer;
color: var(--primary-color);
}
.title {
text-align: center;
font-weight: bold;
margin: 20px 0;
}
.chart {
min-height: 620px;
}

View file

@ -1,4 +1,14 @@
import { DataColumn, DataTable } from '@umami/react-zen'; import { useMemo, useState } from 'react';
import {
DataColumn,
DataTable,
Row,
Loading,
Column,
ToggleGroup,
ToggleGroupItem,
Text,
} from '@umami/react-zen';
import { import {
useEventDataPropertiesQuery, useEventDataPropertiesQuery,
useEventDataValuesQuery, useEventDataValuesQuery,
@ -6,29 +16,44 @@ import {
} from '@/components/hooks'; } from '@/components/hooks';
import { LoadingPanel } from '@/components/common/LoadingPanel'; import { LoadingPanel } from '@/components/common/LoadingPanel';
import { PieChart } from '@/components/charts/PieChart'; import { PieChart } from '@/components/charts/PieChart';
import { useState } from 'react';
import { CHART_COLORS } from '@/lib/constants'; import { CHART_COLORS } from '@/lib/constants';
import styles from './EventProperties.module.css'; import { ListTable } from '@/components/metrics/ListTable';
export function EventProperties({ websiteId }: { websiteId: string }) { export function EventProperties({ websiteId }: { websiteId: string }) {
const [propertyName, setPropertyName] = useState(''); const [propertyName, setPropertyName] = useState('');
const [eventName, setEventName] = useState(''); const [eventName, setEventName] = useState('');
const [propertyView, setPropertyView] = useState('table');
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const { data, isLoading, isFetched, error } = useEventDataPropertiesQuery(websiteId); const { data, isLoading, isFetching, error } = useEventDataPropertiesQuery(websiteId);
const { data: values } = useEventDataValuesQuery(websiteId, eventName, propertyName); const { data: values } = useEventDataValuesQuery(websiteId, eventName, propertyName);
const chartData =
propertyName && values const propertySum = useMemo(() => {
? { return values?.reduce((sum, { total }) => sum + total, 0) ?? 0;
labels: values.map(({ value }) => value), }, [values]);
datasets: [
{ const chartData = useMemo(() => {
data: values.map(({ total }) => total), if (!propertyName || !values) return null;
backgroundColor: CHART_COLORS, return {
borderWidth: 0, labels: values.map(({ value }) => value),
}, datasets: [
], {
} data: values.map(({ total }) => total),
: null; backgroundColor: CHART_COLORS,
borderWidth: 0,
},
],
};
}, [propertyName, values]);
const tableData = useMemo(() => {
if (!propertyName || !values || propertySum === 0) return [];
return values.map(({ value, total }) => ({
x: value,
y: total,
z: 100 * (total / propertySum),
}));
}, [propertyName, values, propertySum]);
const handleRowClick = row => { const handleRowClick = row => {
setEventName(row.eventName); setEventName(row.eventName);
@ -36,32 +61,37 @@ export function EventProperties({ websiteId }: { websiteId: string }) {
}; };
return ( return (
<LoadingPanel isLoading={isLoading} isFetched={isFetched} data={data} error={error}> <LoadingPanel isLoading={isLoading} isFetching={isFetching} data={data} error={error}>
<div className={styles.container}> <Column>
<DataTable data={data} cardMode={false} className={styles.table}> <DataTable data={data}>
<DataColumn name="eventName" label={formatMessage(labels.name)}> <DataColumn id="eventName" label={formatMessage(labels.name)}>
{row => ( {(row: any) => <Row onClick={() => handleRowClick(row)}>{row.eventName}</Row>}
<div className={styles.link} onClick={() => handleRowClick(row)}>
{row.eventName}
</div>
)}
</DataColumn> </DataColumn>
<DataColumn name="propertyName" label={formatMessage(labels.property)}> <DataColumn id="propertyName" label={formatMessage(labels.property)}>
{row => ( {(row: any) => <Row onClick={() => handleRowClick(row)}>{row.propertyName}</Row>}
<div className={styles.link} onClick={() => handleRowClick(row)}>
{row.propertyName}
</div>
)}
</DataColumn> </DataColumn>
<DataColumn name="total" label={formatMessage(labels.count)} alignment="end" /> <DataColumn id="total" label={formatMessage(labels.count)} align="end" />
</DataTable> </DataTable>
{propertyName && ( {propertyName && (
<div className={styles.chart}> <Column>
<div className={styles.title}>{propertyName}</div> <Row gap justifyContent="space-between">
<PieChart key={propertyName + eventName} type="doughnut" data={chartData} /> <Text>{`${eventName}: ${propertyName}`}</Text>
</div> <ToggleGroup value={[propertyView]} onChange={value => setPropertyView(value[0])}>
<ToggleGroupItem id="table">{formatMessage(labels.table)}</ToggleGroupItem>
<ToggleGroupItem id="chart">{formatMessage(labels.chart)}</ToggleGroupItem>
</ToggleGroup>
</Row>
{!values ? (
<Loading icon="dots" />
) : propertyView === 'table' ? (
<ListTable data={tableData} />
) : (
<PieChart key={propertyName + eventName} type="doughnut" chartData={chartData} />
)}
</Column>
)} )}
</div> </Column>
</LoadingPanel> </LoadingPanel>
); );
} }

View file

@ -51,7 +51,6 @@ export const labels = defineMessages({
data: { id: 'label.data', defaultMessage: 'Data' }, data: { id: 'label.data', defaultMessage: 'Data' },
trackingCode: { id: 'label.tracking-code', defaultMessage: 'Tracking code' }, trackingCode: { id: 'label.tracking-code', defaultMessage: 'Tracking code' },
shareUrl: { id: 'label.share-url', defaultMessage: 'Share URL' }, shareUrl: { id: 'label.share-url', defaultMessage: 'Share URL' },
share: { id: 'label.share', defaultMessage: 'Share' },
actions: { id: 'label.actions', defaultMessage: 'Actions' }, actions: { id: 'label.actions', defaultMessage: 'Actions' },
domain: { id: 'label.domain', defaultMessage: 'Domain' }, domain: { id: 'label.domain', defaultMessage: 'Domain' },
websiteId: { id: 'label.website-id', defaultMessage: 'Website ID' }, websiteId: { id: 'label.website-id', defaultMessage: 'Website ID' },
@ -337,6 +336,8 @@ export const labels = defineMessages({
online: { id: 'label.online', defaultMessage: 'Online' }, online: { id: 'label.online', defaultMessage: 'Online' },
preferences: { id: 'label.preferences', defaultMessage: 'Preferences' }, preferences: { id: 'label.preferences', defaultMessage: 'Preferences' },
location: { id: 'label.location', defaultMessage: 'Location' }, location: { id: 'label.location', defaultMessage: 'Location' },
chart: { id: 'label.chart', defaultMessage: 'Chart' },
table: { id: 'label.table', defaultMessage: 'Table' },
}); });
export const messages = defineMessages({ export const messages = defineMessages({

View file

@ -62,7 +62,7 @@ export function PagesTable({ allowFilter, ...props }: PagesTableProps) {
{...props} {...props}
title={formatMessage(labels.pages)} title={formatMessage(labels.pages)}
type={view} type={view}
metric={formatMessage(labels.views)} metric={formatMessage(labels.visitors)}
dataFilter={emptyFilter} dataFilter={emptyFilter}
renderLabel={renderLink} renderLabel={renderLink}
> >

View file

@ -35,6 +35,7 @@ export const EVENT_COLUMNS = [
'query', 'query',
'event', 'event',
'tag', 'tag',
'host',
]; ];
export const SESSION_COLUMNS = [ export const SESSION_COLUMNS = [
@ -46,7 +47,6 @@ export const SESSION_COLUMNS = [
'country', 'country',
'city', 'city',
'region', 'region',
'hostname',
]; ];
export const FILTER_GROUPS = { export const FILTER_GROUPS = {

View file

@ -18,6 +18,12 @@ async function relationalQuery(websiteId: string, column: string, filters: Query
const { startDate, endDate, search } = filters; const { startDate, endDate, search } = filters;
let searchQuery = ''; let searchQuery = '';
let excludeDomain = '';
if (column === 'referrer_domain') {
excludeDomain = `and website_event.referrer_domain != website_event.hostname
and website_event.referrer_domain != ''`;
}
if (search) { if (search) {
if (decodeURIComponent(search).includes(',')) { if (decodeURIComponent(search).includes(',')) {
@ -46,6 +52,7 @@ async function relationalQuery(websiteId: string, column: string, filters: Query
where website_event.website_id = {{websiteId::uuid}} where website_event.website_id = {{websiteId::uuid}}
and website_event.created_at between {{startDate}} and {{endDate}} and website_event.created_at between {{startDate}} and {{endDate}}
${searchQuery} ${searchQuery}
${excludeDomain}
group by 1 group by 1
order by 2 desc order by 2 desc
limit 10 limit 10
@ -66,6 +73,11 @@ async function clickhouseQuery(websiteId: string, column: string, filters: Query
const { startDate, endDate, search } = filters; const { startDate, endDate, search } = filters;
let searchQuery = ''; let searchQuery = '';
let excludeDomain = '';
if (column === 'referrer_domain') {
excludeDomain = `and referrer_domain != hostname and referrer_domain != ''`;
}
if (search) { if (search) {
searchQuery = `and positionCaseInsensitive(${column}, {search:String}) > 0`; searchQuery = `and positionCaseInsensitive(${column}, {search:String}) > 0`;
@ -96,6 +108,7 @@ async function clickhouseQuery(websiteId: string, column: string, filters: Query
where website_id = {websiteId:UUID} where website_id = {websiteId:UUID}
and created_at between {startDate:DateTime64} and {endDate:DateTime64} and created_at between {startDate:DateTime64} and {endDate:DateTime64}
${searchQuery} ${searchQuery}
${excludeDomain}
group by 1 group by 1
order by 2 desc order by 2 desc
limit 10 limit 10

View file

@ -38,9 +38,7 @@ async function relationalQuery(
websiteId, websiteId,
eventType: column === 'event_name' ? EVENT_TYPE.customEvent : EVENT_TYPE.pageView, eventType: column === 'event_name' ? EVENT_TYPE.customEvent : EVENT_TYPE.pageView,
}, },
{ { joinSession: SESSION_COLUMNS.includes(type) },
joinSession: SESSION_COLUMNS.includes(type) || column === 'referrer_domain',
},
); );
let entryExitQuery = ''; let entryExitQuery = '';
@ -72,7 +70,7 @@ async function relationalQuery(
return rawQuery( return rawQuery(
` `
select ${column} x, select ${column} x,
${column === 'referrer_domain' ? 'count(distinct website_event.session_id)' : 'count(*)'} as y count(distinct website_event.session_id) as y
from website_event from website_event
${joinSessionQuery} ${joinSessionQuery}
${cohortQuery} ${cohortQuery}
@ -132,8 +130,9 @@ async function clickhouseQuery(
sql = ` sql = `
select ${column} x, select ${column} x,
${column === 'referrer_domain' ? 'uniq(session_id)' : 'count(*)'} as y uniq(website_event.session_id) as y
from website_event from website_event
${cohortQuery}
${entryExitQuery} ${entryExitQuery}
where website_id = {websiteId:UUID} where website_id = {websiteId:UUID}
and created_at between {startDate:DateTime64} and {endDate:DateTime64} and created_at between {startDate:DateTime64} and {endDate:DateTime64}
@ -147,28 +146,27 @@ async function clickhouseQuery(
`; `;
} else { } else {
let groupByQuery = ''; let groupByQuery = '';
let columnQuery = `arrayJoin(${column})`; let columnQuery = `session_id s, arrayJoin(${column})`;
if (column === 'referrer_domain') { if (column === 'referrer_domain') {
excludeDomain = `and t != hostname and t != ''`; excludeDomain = `and t != ''`;
columnQuery = `session_id s, arrayJoin(${column})`;
} }
if (type === 'entry') { if (type === 'entry') {
columnQuery = `visit_id x, argMinMerge(entry_url)`; columnQuery = `session_id s, argMinMerge(entry_url)`;
} }
if (type === 'exit') { if (type === 'exit') {
columnQuery = `visit_id x, argMaxMerge(exit_url)`; columnQuery = `session_id s, argMaxMerge(exit_url)`;
} }
if (type === 'entry' || type === 'exit') { if (type === 'entry' || type === 'exit') {
groupByQuery = 'group by x'; groupByQuery = 'group by s';
} }
sql = ` sql = `
select g.t as x, select g.t as x,
${column === 'referrer_domain' ? 'uniq(s)' : 'count(*)'} as y uniq(s) as y
from ( from (
select ${columnQuery} as t select ${columnQuery} as t
from website_event_stats_hourly as website_event from website_event_stats_hourly as website_event

View file

@ -17,7 +17,6 @@ async function relationalQuery(websiteId: string, sessionId: string) {
select id, select id,
distinct_id as "distinctId", distinct_id as "distinctId",
website_id as "websiteId", website_id as "websiteId",
hostname,
browser, browser,
os, os,
device, device,
@ -37,7 +36,6 @@ async function relationalQuery(websiteId: string, sessionId: string) {
session.distinct_id, session.distinct_id,
website_event.visit_id, website_event.visit_id,
session.website_id, session.website_id,
website_event.hostname,
session.browser, session.browser,
session.os, session.os,
session.device, session.device,
@ -54,8 +52,8 @@ async function relationalQuery(websiteId: string, sessionId: string) {
join website_event on website_event.session_id = session.session_id join website_event on website_event.session_id = session.session_id
where session.website_id = {{websiteId::uuid}} where session.website_id = {{websiteId::uuid}}
and session.session_id = {{sessionId::uuid}} and session.session_id = {{sessionId::uuid}}
group by session.session_id, session.distinct_id, visit_id, session.website_id, website_event.hostname, session.browser, session.os, session.device, session.screen, session.language, session.country, session.region, session.city) t group by session.session_id, session.distinct_id, visit_id, session.website_id, session.browser, session.os, session.device, session.screen, session.language, session.country, session.region, session.city) t
group by id, distinct_id, website_id, hostname, browser, os, device, screen, language, country, region, city; group by id, distinct_id, website_id, browser, os, device, screen, language, country, region, city;
`, `,
{ websiteId, sessionId }, { websiteId, sessionId },
).then(result => result?.[0]); ).then(result => result?.[0]);
@ -69,7 +67,6 @@ async function clickhouseQuery(websiteId: string, sessionId: string) {
select id, select id,
websiteId, websiteId,
distinctId, distinctId,
hostname,
browser, browser,
os, os,
device, device,
@ -89,7 +86,6 @@ async function clickhouseQuery(websiteId: string, sessionId: string) {
distinct_id as distinctId, distinct_id as distinctId,
visit_id, visit_id,
website_id as websiteId, website_id as websiteId,
hostname,
browser, browser,
os, os,
device, device,
@ -105,8 +101,8 @@ async function clickhouseQuery(websiteId: string, sessionId: string) {
from website_event_stats_hourly from website_event_stats_hourly
where website_id = {websiteId:UUID} where website_id = {websiteId:UUID}
and session_id = {sessionId:UUID} and session_id = {sessionId:UUID}
group by session_id, distinct_id, visit_id, website_id, hostname, browser, os, device, screen, language, country, region, city) t group by session_id, distinct_id, visit_id, website_id, browser, os, device, screen, language, country, region, city) t
group by id, websiteId, distinctId, hostname, browser, os, device, screen, language, country, region, city; group by id, websiteId, distinctId, browser, os, device, screen, language, country, region, city;
`, `,
{ websiteId, sessionId }, { websiteId, sessionId },
).then(result => result?.[0]); ).then(result => result?.[0]);