Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

2. A guided tour

Twelve short steps through the language. Each one adds one idea.

2.1 Read a collection

on users

Every document of users. from users is the same.

2.2 Keep some rows

on users | where age >= 18 and city == "Paris"
{"name":"Alice","age":31,"city":"Paris",…}
{"name":"Dan","age":28,"city":"Paris",…}

where keeps the rows whose predicate is true. Conditions combine with and, or, not, and parentheses.

| separates stages. A query without | can separate them with ;, or write one stage per line:

on users
where age >= 18
  and city == "Paris"

Both styles read the same (3.2); this book writes |.

2.3 Choose and compute fields

on orders | select order_id, price * qty as total, upper(status) as status
{"order_id":1,"status":"PAID","total":20.0}
…

select keeps only what it lists (plus _id). To add fields and keep the rest, use derive:

on orders | derive total = price * qty, big = total > 100

2.4 Sort and page

on orders | sort price * qty desc | limit 3

sort takes fields or expressions; limit and skip page. A sort followed by limit runs as a bounded Top-N.

2.5 Aggregate

on orders | where status == "paid" | group | by region | sum qty as units | avg price | count as orders | end
{"avg_price":54.75,"orders":2,"region":"EU","units":3}
{"avg_price":130.0,"orders":2,"region":"US","units":5}

The compound group opens a sub-pipeline: one by, then any number of measures, closed by end. The one-line form covers the common cases: group region, qty sums qty per region.

2.6 Join

on orders | lookup products on code == product into product

Each order receives an array product holding the matching products. For anything richer than one equality, write the sub-pipeline:

on users as u
| lookup orders as o
    | where o.user == u.name and o.status == "paid"
    | select order_id, price
    | into paid_orders
| end

2.7 Stack two sources

on actual | select month, amount | union | on budget | select month, amount | end

2.8 Reuse a value

let $since = "2026-02", $min = 50
| on orders
| where month >= $since and price * qty > $min

let names values once per query. $name can also come from the request (params).

2.9 Name a query: a view

define view sales.paid
| description "Paid orders with their total"
| exec
  | on orders | where status == "paid" | derive total = price * qty
| end
| end

Then read it like a collection:

on view sales.paid | group | by region | sum total | end

2.10 Keep it computed: a materialized view

define view sales.by_month | materialized | exec
  | on view sales.paid | group | by month, region | sum total | end
| end
| end

The first read computes the rows and keeps them. Later reads use them, until orders changes, or a view it reads is redefined.

2.11 Write

on users | insert {name: "Eve", age: 22, city: "Lyon"}
on users | where name == "Bob" | set age = age + 1
on orders | where status == "cancelled" | delete
on orders | group | by region | sum qty as units | end | into region_totals

Every write query is one transaction.

2.12 Look under the hood

explain on orders | where qty > 1 | sort price * qty desc | limit 3
on _views | where state == "active" | select name, version, reads
on _memory | where scope == "global"

explain shows the plan without running it; system collections expose views, caches and engine state.


Next: the lexical structure, or jump to the stage reference.