Skip to content

Aggregations

Count, sum, average, min and max over a collection, grouped by fields or time buckets.

GET /api/v1/<collection>/_aggregate

Aggregates run over exactly the records a list would return, after filter, search and the collection’s list rule. A caller can never aggregate rows they couldn’t list. If the list rule is admin-only (""), non-admins get 403.

ParamDefaultNotes
aggcountComma-separated: count, count(f) (non-null values), sum(f), avg(f), min(f), max(f). Up to 10. sum / avg need a number field.
groupBy—Up to 3 fields. Date fields (date, created, updated) take a bucket: :hour, :day, :week, :month, :year (UTC).
filter—Same expression language as list.
search—Full-text search.
sortsee belowA groupBy field or an aggregate alias, - for descending. Comma-separated.
limit100Max groups returned (max 1000).

Each result row has the groupBy keys plus one key per aggregate: count, count_<f>, sum_<f>, avg_<f>, min_<f>, max_<f>. Without sort, time buckets come oldest first and other groups biggest first.

Revenue per status:

GET /api/v1/orders/_aggregate?agg=count,sum(amount)&groupBy=status&sort=-sum_amount
{ "data": [
{ "status": "paid", "count": 120, "sum_amount": 48210.5 },
{ "status": "pending", "count": 14, "sum_amount": 3120 }
] }

Signups per month:

GET /api/v1/users/_aggregate?groupBy=created:month
{ "data": [ { "created": "2026-01", "count": 312 }, { "created": "2026-02", "count": 287 } ] }

Totals with no grouping:

GET /api/v1/orders/_aggregate?agg=count,avg(amount),max(amount)

With the SDK:

const rows = await vb.collection("orders").aggregate({
agg: ["count", "sum(amount)"],
groupBy: "status",
sort: "-sum_amount",
});
  • Encrypted fields: only ciphertext is stored.
  • Passwords, files, JSON, vectors, geo points and multi-value select fields.
  • Auth collections’ built-in columns (email, email_verified).

Any of these, or an unknown field, returns 400.