Skip to content

feat: aggregate annotations (annotate / having / order_by)#1742

Open
collerek wants to merge 16 commits into
masterfrom
feat/aggregation-annotations
Open

feat: aggregate annotations (annotate / having / order_by)#1742
collerek wants to merge 16 commits into
masterfrom
feat/aggregation-annotations

Conversation

@collerek

Copy link
Copy Markdown
Collaborator

Adds per-parent aggregate annotations to querysets: annotate(task_count=ormar.Count("tasks")) with Count/Sum/Avg/Min/Max over a relation or related column, compiled as a single pre-grouped derived-table join (one pass, 1:1 with the parent, so it composes with select_related and pagination). Supports ordering by an annotation (order_by("-task_count")), filtering with having(task_count__gt=0), and reading results through values()/values_list(). Count over empty children is 0 (COALESCE); other functions are NULL. Works over reverse ForeignKey and — for bare Count — many-to-many. Verified on SQLite, PostgreSQL and MySQL at 100% coverage.

Closes #566.

Partially addresses #266: this covers aggregate functions, ordering and having for per-parent aggregates, but not group_by/rollups (grouping by a non-unique column), which remains as follow-up work.

collerek added 16 commits July 14, 2026 19:44
Locks down that .annotate(...).values() with no explicit field list still
carries the annotation alongside the regular model columns on every row.
Add docs/queries/aggregate-annotations.md covering annotate/having,
ordering by an annotation (closes #566), Count/Sum/Avg/Min/Max, the
zero-vs-NULL empty-relation semantics, many-to-many restrictions, and
composition with select_related/pagination; link it from mkdocs.yml nav
and add a one-line feature entry to README.md/docs/index.md.

Also fixes a dialect-specific bug surfaced while verifying docs examples
against PostgreSQL: the pagination subquery used for select_related +
limit/offset ordered by an annotation's raw (non-coalesced) derived column
instead of its own already-coalesced result column, so a childless
parent's NULL count sorted as the largest value under PostgreSQL's default
DESC ordering, ranking it ahead of real matches. Ordering now reuses the
same coalesced column used in the main query, closing #266's example.
@codspeed-hq

codspeed-hq Bot commented Jul 15, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 98 untouched benchmarks


Comparing feat/aggregation-annotations (7de7b80) with master (e910772)1

Open in CodSpeed

Footnotes

  1. No successful run was found on master (710cdbb) during the generation of this report, so e910772 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Sorting on number of reversed FK

1 participant