Skip to main content

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.

Synchronous execution

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

MethodReturnsDataUse when
query(text, opts?)QueryResultmaterialized arrayyou just want results
parse(text, opts?)ASTNode[]n/ayou need the AST
buildPlan(ast, opts?)PlanOperatorn/ayou want to inspect/transform the plan
executePlan(plan, params?)QueryResultlazy iterableyou want streaming / early exit