PostgreSQL-only aggregates (ArrayAgg, StringAgg, JSONBAgg, BoolAnd/Or)

Django ORM PostgreSQL May 22, 2026 python

These aggregates exist only on PostgreSQL.

python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# ======================================================================
# These aggregates exist only on PostgreSQL. `ArrayAgg` gathers a column into an
# array, `StringAgg` joins it into one delimited string, `JSONBAgg` builds a
# JSON array, and `BoolAnd`/`BoolOr` reduce booleans. `default=Value([])` keeps
# authors with no books from collapsing to NULL.
# ======================================================================

# --- Django ORM ---
Author.objects.annotate(
    titles=ArrayAgg("books__title", distinct=True, default=Value([])),
    csv=StringAgg("books__title", delimiter=", ", default=Value("")),
    as_json=JSONBAgg("books__title", default=Value([])),
    all_active=BoolAnd("books__is_active"),
    any_active=BoolOr("books__is_active"),
    n=Count("books"),
)

# --- generated SQL ---
#   SELECT "examples_author"."id", "examples_author"."name", "examples_author"."bio", "examples_author"."born", "examples_author"."rating", "examples_author"."nickname", COALESCE(ARRAY_AGG(DISTINCT "examples_book"."title" ), '{}'::varchar(200)[]) AS "titles", COALESCE(STRING_AGG("examples_book"."title", ', ' ), '') AS "csv", COALESCE(JSONB_AGG("examples_book"."title" ), '[]'::jsonb) AS "as_json", BOOL_AND("examples_book"."is_active") AS "all_active", BOOL_OR("examples_book"."is_active") AS "any_active", COUNT("examples_book"."id") AS "n"
#   FROM "examples_author"
#   LEFT OUTER JOIN "examples_book" ON ("examples_author"."id" = "examples_book"."author_id")
#   GROUP BY "examples_author"."id"

# ----------------------------------------------------------------------
# J. K. Rowling (1 book(s))
# ----------------------------------------------------------------------

# Result:
#   titles (ArrayAgg): ['Harry Potter']
#   csv (StringAgg): Harry Potter
#   json (JSONBAgg): ['Harry Potter']
#   all_active=True  any_active=True

# ----------------------------------------------------------------------
# J. R. R. Tolkien (2 book(s))
# ----------------------------------------------------------------------

# Result:
#   titles (ArrayAgg): ['The Hobbit', 'The Lord of the Rings']
#   csv (StringAgg): The Hobbit, The Lord of the Rings
#   json (JSONBAgg): ['The Hobbit', 'The Lord of the Rings']
#   all_active=True  any_active=True

# ----------------------------------------------------------------------
# Karl Müller (1 book(s))
# ----------------------------------------------------------------------

# Result:
#   titles (ArrayAgg): ['Postgres for Authors']
#   csv (StringAgg): Postgres for Authors
#   json (JSONBAgg): ['Postgres for Authors']
#   all_active=True  any_active=True