Lesson 4 — Aggregations

Lesson 4 — Aggregations #

From counts to histograms to composite paging — over sales and logs, with known answers you can verify by hand.

The use case #

Dashboards, reports, and faceted navigation — wherever the deliverable is not a page of hits but an answer. The questions this lesson answers:

  • “What is the average / min / max price?” — metric aggregations.
  • “How is revenue split by status?” — terms buckets.
  • “Volume per week / per price band” — histograms.
  • “Every (merchant, day) pair, complete — not just the top N” — composite aggregations with after cursors.
  • “Just the number, skip the hits” — size: 0.

Metric aggregations #

One number out: sum, avg, min, max, stats (all of them at once), cardinality (distinct values):

Four distinct product types; stats gives you min/max/sum/avg/count in one round trip.

The same question as SQL — global aggregates are the M1 subset’s scalar lane (see the SQL reference):

120 sales, prices 15–60, four distinct types — one row, no size: 0 to remember.

Bucket aggregations #

terms builds a bucket per value — the dataset’s known answer is t-shirt 60, hat 30, mug 20, sticker 10:

As SQL that is one GROUP BY — order by the count to get the terms ordering:

Same answer, column names instead of a bucket tree: t-shirt 60, hat 30, mug 20, sticker 10.

One bucket per value — every document falls into exactly one, and the count is the answer:

graph LR subgraph sales["the 120 sales"] d1("t-shirt") d2("t-shirt") d3("hat") d4("mug") d5("sticker") end d1 -->|"type"| b1["t-shirt — 60"] d2 -->|"type"| b1 d3 -->|"type"| b2["hat — 30"] d4 -->|"type"| b3["mug — 20"] d5 -->|"type"| b4["sticker — 10"]

histogram slices a number into fixed intervals; date_histogram slices time — 92 sales in 2024, 28 in 2025:

The SQL spelling is DATE_TRUNC as the grouping key:

92 rows land in the 2024 bucket, 28 in 2025 — the same split, as rows.

Sub-aggregations #

Every bucket runs its own aggs — revenue per type as sum of price inside a terms bucket:

A sub-aggregation is just another column in SQL — the metric aggregates over each group:

Filtered aggregations #

filter scopes an aggregation to a query; filters builds named buckets — the logs level split (error 25 / warn 25 / info 100):

One GROUP BY answers the same split in SQL (a WHERE scopes it first if you need only part of the data):

error 25, info 100, warn 25 — sorted by the key, so the rows read like an index.

Paging through buckets #

composite pages through multi-dimensional buckets with an after cursor — for dashboards, not top-10 lists:

SQL pages the same walk with a keyset cursor — LIMIT bounds the page, the envelope’s cursor continues it (the full playground’s SQL mode carries the Next-page button):

What you learned #

  • Metric aggs summarize; bucket aggs group; sub-aggs nest.
  • size: 0 skips hit assembly — the aggregations ARE the result.
  • composite + after cursors for complete bucket walks.
  • Every aggregation on this page has a SQL spelling: global metrics are scalar aggregates, buckets are GROUP BY, sub-aggs are more columns, composite walks are cursor pages.

Next: Lesson 5 — graph traversal.

Calendar October 6, 2026
Edit Edit this page