Přeskočit na obsah

Agregace v aplikaci nad API s row-capem tiše počítá jen z prvních N řádků

import { Aside } from ‘@astrojs/starlight/components’;

Admin dashboard zobrazuje graf návštěvnosti po dnech a top stránky. Čísla vypadají věrohodně (nejsou nulová), ale neodpovídají realitě — okno se ~1,6M záznamy ukazuje řádově stovky. Žádná chyba v lozích; bug běží měsíce bez povšimnutí, odhalí ho až porovnání s nezávislým zdrojem (GA, přímý SQL COUNT).

Endpoint táhl raw řádky a agregoval v aplikaci:

// špatně: PostgREST tiše vrátí max 1000 řádků (max-rows default)
const { data: rows } = await db.from('page_views')
.select('created_at')
.gte('created_at', thirtyDaysAgo);
const dayCounts = groupByDay(rows); // agreguje jen prvních 1000 řádků

PostgREST (a řada dalších API vrstev) má implicitní limit počtu vrácených řádků a překročení nesignalizuje chybou — prostě vrátí prvních N. Aplikační agregace pak mlčky počítá ze zlomku dat. Stejná past: každý .select() bez explicitní paginace použitý jako podklad pro součty, žebříčky nebo migrační/opravné skripty.

Agregovat v DB a přenášet jen výsledek — pro těžká okna navíc denní rollup:

-- rollup uzavřených dnů (cron, idempotentní ON CONFLICT DO UPDATE)
CREATE TABLE page_views_daily (day date PRIMARY KEY, views bigint, unique_ips bigint, top_paths jsonb);
-- dnešek živě, jedna SQL funkce = žádný row-cap
CREATE FUNCTION page_views_live_today() RETURNS TABLE(views bigint, unique_ips bigint, top_paths jsonb) ...

Endpoint pak čte pár desítek rollup řádků + jeden živý agregát. Bonus: rollup přežije retenční mazání raw tabulky.

  • Porovnat dashboard s nezávislým zdrojem (GA4, přímý SELECT count(*)).
  • Grep na select( + následnou JS agregaci (for/reduce nad výsledkem) nad tabulkami s > tisíci řádky.
  • V PostgREST nastavit max-rows vědomě a vždy používat .range() u výčtů.
Přidal aiarchitekt.cz · 6. 7. 2026 2:00
Provozuje aiarchitekt.cz