Running Queries
db.query() is
the one-shot path: it parses, plans, optimizes, executes, and collects the
results into an array.
const result = db.query('SELECT a FROM t');
result.data; // materialized array
result.schema; // ['a']
The recipes below cover what to do when that is not quite what you need. If you want to inspect or rewrite the plan in between, see Inspecting Plans.
Choose the language for one query
When several languages are loaded,
mainLang
decides which one parses a query. Override it per query with the
mainLang
option, using the lower-cased language name:
db.query('MATCH (p:Person) RETURN p.name AS name', { mainLang: 'cypher' });
To switch languages inside a single query instead, use a LANG block; see
Cross-language Queries.
Stream results and stop early
query() collects
every row before returning. To pull rows on demand, so you can process a large
result incrementally or stop before computing all of it, run the stages yourself
and finish with
executePlan,
whose
data is a
lazy iterable:
const ast = db.parse('SELECT a FROM t');
const plan = db.buildPlan(ast.at(-1));
const result = db.executePlan(plan);
for (const row of result.data) {
// rows are produced on demand
if (done(row)) break; // stop early without computing the rest
}
To materialize a streamed result after all, spread it:
const rows = [...result.data].
parse returns an
array of AST nodes, one per top-level statement, which is why the example
takes .at(-1).
query() behaves
the same way: given several statements, only the last one is executed.
Execution is synchronous and single-threaded; iterating data pulls rows
through the operator tree on the calling thread. Functions and aggregates used
in queries must therefore be synchronous. See
Limitations.
Pass runtime values
Pass values into a query with
boundParams
rather than interpolating them into the query string. Parameters are referenced
by name, and the syntax depends on the language: SQL uses :name (or ?name),
Cypher and XQuery use $name.
// SQL
db.query('SELECT n FROM nums WHERE n > :threshold', {
boundParams: { threshold: 15 },
});
// Cypher
db.query('MATCH (a) WHERE a.id > $id RETURN a', {
mainLang: 'cypher',
boundParams: { id: 13 },
});
executePlan
accepts the same parameter map as its second argument, so a plan you built once
can be re-executed with different values.
The four entry points at a glance
| Method | Returns | Data | Use when |
|---|---|---|---|
query(text, opts?) | QueryResult | materialized array | you just want results |
parse(text, opts?) | ASTNode[] | n/a | you need the AST |
buildPlan(ast, opts?) | PlanOperator | n/a | you want to inspect/transform the plan |
executePlan(plan, params?) | QueryResult | lazy iterable | you want streaming / early exit |