Results
Read query state, rows, columns, paging and debug details
Each query exposes its current state and result as properties. Read them from your app.subscribe() callback.
State and errors
| Member | Does |
|---|---|
query.state | 'idle', 'executing', 'success' or 'error' |
query.result | The result, or undefined before the first success. It is kept while the query re-executes, so you can render stale data under a spinner. |
query.error | The error when state === 'error'. See Errors. |
query.setSort(sorts) / query.sort | Sets or reads the sort applied to the result. See Sorting. |
query.hasMore / query.fetchMore() | Pages through the result. See Paging. |
query.select(rows, { fields? }) / query.selectedRows | Selects rows for cross-filtering, and reads which rows are selected. |
query.abort() | Cancels this query's in-flight request. |
query.locate() | Scrolls to the elements marked with this query and highlights them for a moment. See Page structure. |
query.subscribe(fn) | A change listener for just this query. |
A page usually renders four states for each query: loading (executing), an error (error, showing query.error.message), a result with rows, and a result with no rows. Write the empty state in words, such as "No sales this week", rather than showing a bare zero.
Result shape
query.result.columns // [{ name, fieldName, modelId?, label, adhoc, isMeasure, aggregation? }]
query.result.rows // [{ period: '2026-01-01', revenue: 1234.5 }, ...]
query.result.meta // { numRows, page?, pageSize? }- Row keys are the aliases your AQL declared, such as
periodandrevenue. They matchcolumn.name.column.fieldNameis the underlying field, which you only need for debugging. column.labelis a display label. Prefer it for axis and header text.column.adhocmarks a query-local expression, andcolumn.isMeasurea measure. Neither can be used for cross-filtering.
Values are raw
Values are never formatted. Format numbers and dates yourself, for example with Intl.NumberFormat and toLocaleDateString.
- Decimal values can arrive as strings (
"97537.24") to keep their precision. Convert withNumber(...)before charting a measure. - Dates arrive as ISO strings (
"2025-06-01T00:00:00Z").
Log rows[0] on the first success to confirm the value types rather than guessing.
Sorting
query.setSort([{ field: 'revenue', direction: 'desc' }])
await app.execute()field is a result column name, the alias from your AQL. direction is 'asc' (the default) or 'desc'. setSort([]) restores the sort in the AQL. Re-run with app.execute() after changing the sort.
Paging
A query without pageSize is not paged: it returns every row in one result.
Declare pageSize, a whole number of at least 1, to get the result a page at a time. Any other value throws a ValidationError. result.meta.page and result.meta.pageSize are present only for a paged query.
const orders = app.createQuery('orders', { dataset: 'sales', aql, pageSize: 100 })
if (orders.hasMore) await orders.fetchMore() // appends the next page- Unlike
app.execute(),fetchMore()rejects on failure. - On a query with no
pageSize,hasMoreis alwaysfalse, andfetchMore()rejects with aValidationError. - A pivot query (
rows { }/columns { }) can't be paged, so it must not declarepageSize. - To give the reader every row of a paged query as a file, use
query.export()rather than building one fromresult.rows.
Debug information
result.debug holds:
executedAql: for an AQL query, your AQL with the reader's filters, sorts and date drills applied. When a control seems to do nothing, log this first.executedSql: the SQL that ran on the warehouse.executedAt: when it ran.fromCache: whether the result came from cache.
console.log(query.result.debug?.executedAql)Under anfra serve, the Inspect panel shows the same for every query. See Build a data app.
Related
- Queries: declare the data.
- Errors: what
query.errorholds. - Cross-filtering: turn selected rows into filters.