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

6. Anatomy of a query

[explain] [let … |]* <source> ( | <stage> )*

Here | stands for any stage separator: |, or ; and line breaks in a query that holds no | (3.2).

A request is, in order: an optional explain, zero or more let headers, one source, and zero or more stages. A request can instead be a view statement (define view …, undefine view …, chapter 11).

6.1 Sources

SourceReads
on <collection>The documents of a collection (from is a synonym)
on <collection> as of <date | generation>The collection as it was then (chapter 8)
on <collection> historyOne row per stored write of the collection
on values [{…}, …]Literal rows
on view <name> [version <n>]A view (chapter 11)

Each takes an optional as <alias>. A query may be the source alone: on users returns every document.

Collections

  • Dotted names work: on shop.orders.
  • A collection exists from its first write; reading one that does not exist returns no rows (not an error).
  • In a Place, the source reads only the rows of that Place (and of the App instance, when the request names one).

Aliases

At the top level, on users as u | where u.age > 30 and where age > 30 are the same: the qualifier is dropped before planning (outside string literals), so an alias shadows a field of the same name. In a lookup or union sub-pipeline, the alias names the outer row, and the sub-pipeline’s own alias names the joined row.

Literal rows: values

on values [{code: "FR", rate: 0.2}, {code: "DE", rate: 0.19}] | where rate > 0.19

Objects with bare or quoted keys. values works wherever a collection is read: lookup values […] as r | … | end, union | on values […] | end, the one-line lookup values […] as v on code == account into hit. The rows are written once into a constant collection named after their content (_values.v<hash>): read like any collection (indexes of lookup, streaming), shared by every Place, never writable.

6.2 Stages

Simple stages

| <stage-name> <arguments>

Everything up to the next top-level separator is the stage’s argument text, which the stage’s own grammar reads.

Compound stages and end

Some stages open a sub-pipeline, a sequence of stages closed by | end:

on users
| lookup orders
    | where status == "paid"
    | into paid
| end
| select name, paid
PolicyStagesRule
Always compoundunion, pivot, windowAlways open a sub-pipeline
Compound unless one-linelookup / joinOne-line when the header holds into (lookup t on a == b into f)
Compound when baregroup, loadCompound when written without arguments; one-line otherwise
Never compoundevery other stageAlways simple

Without |, the same query reads:

on users
lookup orders
  where status == "paid"
  into paid
end
select name, paid
  • A missing | end is an error: sub-pipeline opened by stage at … is missing '| end'; written with lines, `lookup` at line 2 opens a block that no `end` closes.
  • An end with nothing open is an error: unexpected 'end' outside a sub-pipeline (`end` at line N closes no block written with lines).
  • Sub-pipelines nest: a lookup inside a union branch inside a view.

The words inside a compound stage are directives, not stages: by, sum, avg… in group; rows, columns, values, aggregate in pivot; partition by, order by, lag… in window; with, chunk in load.

6.3 Placement rules

RuleError
Nothing follows a terminal stage: set, delete, insert, load, into, countoperator … follows a terminal operator
insert is the only stage of its pipelineinsert … must be the only operator
load is the first stageload operator at index N must be first
select, sort, limit, skip appear once per pipeline (first may repeat)limit operator is duplicated
Unknown stage names are refusedunknown stage "frobnicate"
Arguments are checked before any data is readinvalid limit syntax … expected a non-negative integer
Sub-pipelines of lookup and union only read; on, from, with, chunk are refused inside a lookupa planning error naming the stage

6.4 Read and write queries

A query is a write when it holds insert, set, delete, into or load; otherwise it only reads.

  • A read streams its rows as they are produced, within the memory contract of chapter 14.
  • A write runs in one transaction: everything commits, or nothing does.
  • A readOnly request refuses a write (query.read_only_violation), and so do view bodies and let queries.

6.5 Scope: Places and App instances

When a request runs in a Place:

  • every source reads only the rows of that Place (_place), and of the App instance when the request names one (_app_instance);
  • every write stamps its rows with that scope;
  • on view reads the Place’s view of that name, else the standard one;
  • materialized views keep one cache per scope (chapter 12).

The language does not change: the scope is applied by the Core, not written in the query.