Skip to main content
Aggregate functions collapse multiple rows into a single summary value. They are always used together with GROUP BY, which groups rows sharing the same value in one or more fields before the aggregation is applied.

Aggregate vs. scalar functions

Reference

Basic aggregation example

DISTINCT support

Passing true as the second argument (Fluent API) or prefixing the field with DISTINCT (FQL) causes the function to operate only on unique values, ignoring duplicates.
DISTINCT is not supported with COUNT(*). Using it will throw an InvalidArgumentException.

HAVING clause

HAVING filters groups after aggregation, similar to how WHERE filters individual rows before aggregation. You can reference aggregated aliases in the HAVING condition.
You can use HAVING without GROUP BY to filter the entire result set as a single group — useful for checking totals across all rows.

COUNT(*) vs COUNT(field)

COLLECT_OBJECT

Added in 3.1.0.
COLLECT_OBJECT collapses every row in a GROUP BY group into a single array of structured objects. Each row is projected through an inner mini-SELECT (with field aliases and arithmetic), and the resulting list can optionally be sorted with an inner ORDER BY.

Grammar

  • Inner items accept the full FQL expression syntax — column references, scalar functions (CONCAT, ROUND, IF, COALESCE, UPPER, LOWER, …), arithmetic (price * 1.21 AS price_with_vat), and aliases.
  • The optional inner ORDER BY accepts multiple sort keys with ASC / DESC and can reference both source columns and the aliases declared inside COLLECT_OBJECT(...).
  • The aggregate returns array<array<string, mixed>> per group.

FQL example

Fluent API

Build the inner projection with FQL\Query\Builder\CollectObject, then pass it to collectObject() and alias the result with as():
CollectObject::select() accepts the full FQL expression syntax — inline "expr AS alias" and comma-separated lists both work. orderBy(), asc(), and desc() chain just like on the main query.

Notes & limitations

  • Empty groups produce no output row, consistent with the other aggregates.
  • Null values propagate into the produced objects — unlike SUM / AVG, which skip them.
  • Stable sort preserves accumulation order on ties.
  • The inner ORDER BY sees both source columns and the aliases declared inside COLLECT_OBJECT(...).
  • DISTINCT, LIMIT, WHERE, and nested COLLECT_OBJECT are not supported and will throw a clear exception.
  • Aggregates inside COLLECT_OBJECT are accepted but rarely useful — they collapse the accumulated rows to a single output object, so COLLECT_OBJECT(SUM(x)) yields an array of length 1. Prefer scalar aggregates at the outer level alongside COLLECT_OBJECT for per-group summary numbers.