Query Records
Query Records: fetches records of a cloud database class with filter/sort/limit, keeps results live, and outputs them as an array.
Query Records reads a class from the connected cloud database and exposes the matching records on items (an array of record objects), with count, firstItemId and isEmpty alongside. The query — class name, visual or JavaScript filter, sorting, limit and pagination — is configured in the node's parameters. Results are live by default: when a record elsewhere in the app is created, saved or deleted, the node re-checks it against the current query and updates items in place. fetched fires when a fetch completes, failure/error report problems.
When to use it
The starting point of every cloud-data list or lookup in browser logic. For writing data use Create/Save/Delete New Record nodes; for a single record by id use Model2/DbModel2; in cloud functions querying is available too (availableIn: cloud).
At a glance
| Category | Cloud Services |
| Type name | DbCollection2 |
| Available in | browser, cloud |
| SSR compatibility | safe |
| Provided by | noodl-runtime |
Outputs
Values
| Name | Type | Default | Description |
|---|---|---|---|
changedEvent | String | — | create, update, delete, init or resync |
changedRecord | Object | — | The record the change was about. ⚠️ Null on a delete against Directus, which sends only the key — use Changed Record Id, which every backend fills |
changedRecordId | String | — | The id of the changed record, always a string — even where the backend's primary key is an integer |
changedRecords | Array | — | Every record in the change frame; some backends batch |
count | Number | — | How many records are in Items, which Limit caps — turn on Fetch total count for the uncapped figure |
firstItemId | String | — | Id of the first matched record, for feeding a Record node without going through a repeater |
isEmpty | Boolean | — | True when the query matched nothing, and also true before the first query has run |
items | Array | — | Records the query matched, in the order Sort asks for; empty before the first query has run |
realtimeStatus | String | — | connecting, subscribed, interrupted or stopped. Four states rather than a boolean, because "connecting for the first time" and "dropped and retrying" want different things on screen |
subscribed | Boolean | — | True while the backend has confirmed the subscription and is delivering changes |
Signals
| Name | Type | Default | Description |
|---|---|---|---|
changed | Signal | — | Any of the three, and also the backend saying the view may be stale after a reconnect — the one to react to if you do not care which happened |
created | Signal | — | Another client created a record in this collection |
deleted | Signal | — | Another client deleted a record from this collection |
fetched | Signal | — | Fires once the query has returned and Items is up to date |
updated | Signal | — | Another client updated a record in this collection |
Failure outputs
| Name | Type | Default | Description |
|---|---|---|---|
error | String | — | Why the last query failed; empty until one does |
failure | Signal | — | Fires when the query could not be run, after the reason has been reported on the error channel |
realtimeError | Object | — | The last realtime failure, with a code and whether retrying can help; null until one happens |
realtimeFailure | Signal | — | Fires when a subscription cannot connect, is rejected, or has been given up on |
Dynamic ports
This node's port list changes at runtime (runtime-discovered, editor-adapter); the tables above may be incomplete for a given instance.
Filter/sort input ports are generated by the editor from the visual query (QueryRecordsAdapter) and the selected class schema.
Ports at runtime
All inputs are runtime-determined (runtime-discovered + editor-adapter): the class choice, filter values, sort keys and paging inputs are generated from the project's database schema and the visual filter you build in the editor — e.g. each 'value' placeholder in a filter becomes its own input port, and actions like fetch ('storageFetch') are registered on demand. A generator cannot enumerate them statically; an authoring tool should set collectionName and filter parameters, and may wire signals to fetch-related inputs which the runtime registers when used.
Patterns
items→ Repeateritems, with record properties delivered to the item component via Component Inputs: the canonical list page.- Event Receiver
eventReceived→ fetch input: re-run a query on demand from anywhere in the app. - Turn on Subscribe To Changes and wire
Changedback into this node's ownDo: the list stays current without polling, on every backend whose descriptor allows it — SSE on the built-in backend and PocketBase, a WebSocket on Directus. Subscribed→ a status indicator's visibility, so people can see when live updates are actually running rather than assuming.
Watch out for
- Re-querying on a timer to feel 'live' — results already update from cloud events; explicit re-fetch is only needed when the server changed outside those events.
- Treating
Changed Recordas the full record on a delete — delete events carry only primary keys, so it is null and onlyChanged Record Idis populated. - Polling with a Timer while Subscribe To Changes is available on this backend. Subscribe and re-fetch on
Changedinstead. - Assuming
Subscribeddistinguishes 'reconnecting' from 'never connected' — it does not. ReadRealtime Statusfor that.
Examples
List page: Repeater fed by Query Records
The canonical data-list shape. Query Records (DbCollection2) fetches a database class and exposes the result on its items array output; the Repeater (For Each) consumes that array and instantiates its template component once per record. Each record's properties are delivered to the item component through Component Inputs whose names match the record's property names — the item component reads them like any other input. The Repeater and its item template component are separate components by design.
Decoupled communication with Send Event / Receive Event
Events carry a signal (and optional payload values) between components with no wire between them: every Receive Event listening on the same channelName fires when a Send Event on that channel sends. Here a toolbar button broadcasts 'RefreshRequested', and a separate component re-runs its data fetch when it receives the event. Use events when the sender must not know who reacts; for parent↔child data flow prefer Component Inputs/Outputs.
A list that keeps itself current, with Subscribe To Changes
A query is a snapshot — it only refreshes when Do fires. Turning on Subscribe To Changes closes that gap on the Query Records node itself: it holds a live subscription on the collection and fires Changed whenever any client creates, updates or deletes a record, so wiring Changed → Do keeps the list current without polling. Subscribed drives a small 'live' indicator so people can see when realtime updates are actually running, and Realtime Status says which of connecting/subscribed/interrupted it is in. Works on every backend that can push — SSE on the built-in backend and PocketBase, a WebSocket on Directus.
Records on a REST backend: query, create, update, delete
One Record family serves every backend. Query Records fetches on demand into items (re-trigger storageFetch to refresh — a query with realtime off does not re-query itself), Create/Update/Delete Record each act on a store signal and answer done (or failure) followed by completed, and Update and Delete take the record's modelId. After any write the query's storageFetch is re-triggered to refresh the list. No node here names a backend, so all five resolve the project's selected one; set the Backend input to point a single node somewhere else.
Reacting to what another user changed, without owning the query
Subscribe To Changes watches one class on the selected backend and fires signals when anything in it changes — no query, no list, no configuration beyond the class. Here it does the two things it is for at once: changed re-runs a Query Records node so the list on screen stays current, and created drives a 'new order' notice off changedRecord, which the subscription already carries so nothing has to be fetched to show it. subscribed drives a live indicator, so a dropped connection is visible rather than a screen that has quietly stopped updating. Against the built-in backend this needs no Backend setting at all: the picker defaults to the project's active backend and is not even shown when there is only one.
Related nodes
Repeater, Record, Create Record, Filter Records, Cloud Function, Subscribe To Changes
This page is generated from node-catalog-enriched.json. Do not edit it by hand — run npm run docs:nodes to regenerate, and fix the source enrichment instead.