mirror of
https://github.com/stack-auth/stack.git
synced 2026-06-13 21:01:21 +08:00
fix usersByCountry query (#1003)
<!-- Make sure you've read the CONTRIBUTING.md guidelines: https://github.com/stack-auth/stack-auth/blob/dev/CONTRIBUTING.md --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Improvements** * Optimized country-level metrics calculation with intelligent sampling and automatic scaling to project accurate user counts from sample data. * Enhanced data aggregation logic with improved handling of edge cases and invalid entries. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
parent
5c816a02e3
commit
793de9e3a0
@ -14,6 +14,7 @@ type DataPoints = yup.InferType<typeof DataPointsSchema>;
|
||||
|
||||
const METRICS_CACHE_NAMESPACE = "metrics";
|
||||
const ONE_HOUR_MS = 60 * 60 * 1000;
|
||||
const MAX_USERS_FOR_COUNTRY_SAMPLE = 10_000;
|
||||
|
||||
async function withMetricsCache<T>(tenancy: Tenancy, suffix: string, prisma: PrismaClientTransaction, includeAnonymous: boolean = false, loader: () => Promise<T>): Promise<T> {
|
||||
return await getOrSetCacheValue<T>({
|
||||
@ -32,12 +33,20 @@ const DataPointsSchema = yupArray(yupObject({
|
||||
|
||||
|
||||
async function loadUsersByCountry(tenancy: Tenancy, prisma: PrismaClientTransaction, includeAnonymous: boolean = false): Promise<Record<string, number>> {
|
||||
const totalUsers = await prisma.projectUser.count({
|
||||
where: {
|
||||
tenancyId: tenancy.id,
|
||||
...(includeAnonymous ? {} : { isAnonymous: false }),
|
||||
},
|
||||
});
|
||||
const users = await prisma.projectUser.findMany({
|
||||
where: {
|
||||
tenancyId: tenancy.id,
|
||||
...(includeAnonymous ? {} : { isAnonymous: false }),
|
||||
},
|
||||
select: { projectUserId: true },
|
||||
orderBy: { projectUserId: "asc" },
|
||||
take: Math.min(totalUsers, MAX_USERS_FOR_COUNTRY_SAMPLE),
|
||||
});
|
||||
|
||||
if (users.length === 0) {
|
||||
@ -46,6 +55,7 @@ async function loadUsersByCountry(tenancy: Tenancy, prisma: PrismaClientTransact
|
||||
|
||||
const userIds = users.map((user) => user.projectUserId);
|
||||
const userIdArray = Prisma.sql`ARRAY[${Prisma.join(userIds.map((id) => Prisma.sql`${id}`))}]::text[]`;
|
||||
const scalingFactor = totalUsers > users.length ? totalUsers / users.length : 1;
|
||||
|
||||
const rows = await globalPrismaClient.$queryRaw<{ countryCode: string | null, userCount: bigint }[]>(Prisma.sql`
|
||||
WITH latest_ip AS (
|
||||
@ -70,8 +80,15 @@ async function loadUsersByCountry(tenancy: Tenancy, prisma: PrismaClientTransact
|
||||
`);
|
||||
|
||||
return Object.fromEntries(
|
||||
rows.map(({ userCount, countryCode }) => [countryCode, Number(userCount)])
|
||||
.filter(([countryCode]) => countryCode)
|
||||
rows.map(({ userCount, countryCode }) => {
|
||||
if (!countryCode) {
|
||||
return null;
|
||||
}
|
||||
const count = Number(userCount);
|
||||
const estimatedCount = scalingFactor === 1 ? count : Math.round(count * scalingFactor);
|
||||
return [countryCode, estimatedCount] as [string, number];
|
||||
})
|
||||
.filter((entry): entry is [string, number] => entry !== null)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user