DRAFTThis page is not published. Only visible in development mode.

For Loops

A for loop runs its block once per element of a source: a numeric range, or the rows of a query result. It is the construct for "do something with each row" logic - per-row writes, running totals, anything a single pipeline cannot express - without leaving RQL. Like all control flow, it runs inside the request's one transaction.

Over a numeric range

gen::series(from, to) yields the integers from through to, inclusive, as a loop source. The loop variable is an ordinary variable inside the block; state accumulates through reassignment. Run the snippets on this page in order:

$ Iterate a Numeric Range
$ ctrl+enter to run

Over query results

To iterate rows, first bind the query to a frame variable with let, then loop over it. Inside the block, each row's columns are reachable as fields on the loop variable ($row.qty):

$ Iterate Query Results
$ ctrl+enter to run

The binding step is required. Putting the query inline in the loop header is a parse error - for iterates variables and ranges, not subqueries:

$ Inline Sources Must Be Bound First
$ ctrl+enter to run

Loops that write

The block can contain any statement, including writes. Combined with an if guard, a for loop becomes a per-row dispatch: inspect each row, act on the ones that qualify. Every write in the loop commits atomically with the rest of the request:

$ A for Loop That Writes
$ ctrl+enter to run

for or something else?

  • --Known element count or a row set: for. Repeating until a condition flips: a while loop.
  • --Exit or skip decided mid-block: a loop with break and continue.
  • --A per-row transformation with no side effects: not a loop at all - a map over the pipeline says the same thing declaratively and lets the engine do the iterating.
gen::series is a loop source
gen::series feeds for loops; it is not a table and cannot be queried with from. To iterate rows, query them and bind the result to a frame variable first.