Skip to main content

Querying LoraDB with Cypher

LoraDB speaks a pragmatic subset of Cypher. Queries are strings that chain clauses — see the clause reference below, or jump into the Ten-Minute Tour for a guided run-through.

MATCH  (p:Person)-[:WORKS_AT]->(c:Company)
WHERE p.active = true
RETURN p.name, c.name
ORDER BY p.name

Each clause reads the rows emitted by the previous one and passes rows forward. RETURN ends the pipeline.

Anatomy of a query

MATCH  — find patterns                (produces rows)

WHERE — filter rows (drops rows)

WITH — project + optionally group (reshapes rows)

WHERE — filter rows post-aggregate (HAVING-style)

RETURN — project + sort + paginate (final shape)

Not every query uses every stage. The important invariant: each clause sees the rows produced by the previous one.

Clause reference

ClausePurpose
MATCHFind patterns of nodes and relationships
CREATECreate nodes and relationships
WHEREFilter rows
RETURN / WITHProject, rename, order, and page results
ORDER BY / SKIP / LIMITSort and paginate
SET / REMOVE / DELETEMutate existing entities
UNWIND / MERGEIterate over lists; create-or-match
Aggregationcount, collect, avg, and group-by
PathsVariable-length traversals and shortest paths

For copy-paste examples covering every clause, see Query Examples. For a single-page terse reference, see the Cheat sheet.

Where common tasks live

TaskPage
Look up by label + propertyMATCH
Write new nodes/edgesCREATE
UpsertMERGE
Bulk importUNWIND + CREATE
Patch a property mapSET +=
Replace all propertiesSET =
Remove a propertyREMOVE / SET n.p = null
Delete with edgesDETACH DELETE
Top-NORDER BY + LIMIT
Stable paginationKeyset pagination
Group and aggregateAggregation walkthrough
HAVING-style filterWITH WHERE
Anti-joinNOT EXISTS
Shortest pathshortestPath
Inline related listPattern comprehension
Per-row conditional valueCASE expressions
Count rows matching a conditioncount(CASE WHEN THEN 1 END)

Execution model

  • Queries execute atomically per call. There is no explicit transaction boundary.
  • Reads and writes share a single mutex — queries run one at a time. This keeps the model simple and removes classes of concurrency bugs, but it means concurrent reads don't parallelise. See Limitations → Concurrency.
  • Names (labels, relationship types, property keys) are validated against the live graph for MATCH; any name is accepted by CREATE, MERGE, and SET.
  • Unknown function names are rejected at analysis time — see Functions.

Parameters

Any value that isn't a constant should use a parameter. The short version follows; Parameters has the full reference.

MATCH (p:Person) WHERE p.name = $name RETURN p

Parameters are bound at call time from the host language:

Missing parameters resolve to null, which can silently produce empty results — set them or validate inputs before executing.

Parameters vs inline literals

-- Safe (parameterised)
MATCH (u:User) WHERE u.id = $id RETURN u

-- Unsafe if $id came from untrusted input and was inlined
MATCH (u:User) WHERE u.id = 42 RETURN u

Parameters are the only supported way to mix untrusted input into a query. They also let the query planner cache plans across invocations.

Parameter types

Host valueLoraDB type
null / None / undefinedNull
boolBoolean
int (Python) / number (JS, integer) / i64 (Rust)Integer
float (Python) / number (JS, non-integer) / f64 (Rust)Float
str / StringString
list / array / VecList
dict / object / BTreeMapMap
helpers (date(), wgs84(), …)Date, Point, etc.

What's not supported

See Limitations for the full list. Short version: no CALL, no FOREACH, no LOAD CSV, no DDL (CREATE INDEX, constraints), no multi-database (USE).

See also