Skip to main content

Cypher Queries

Query your graph using the openCypher query language.

Setup

import { InMemoryGraphFactory } from 'grafio';
import { CypherEngine } from 'grafio/cypher';

const factory = new InMemoryGraphFactory();
const graph = factory.forGraph('default');
// ... add nodes and edges ...

const engine = new CypherEngine(graph);

Basic Queries

Match Nodes by Type

MATCH (p:Person)
RETURN p.name, p.age
const result = await engine.query(`
MATCH (p:Person)
RETURN p.name, p.age
`);

Filter with WHERE

MATCH (p:Person)
WHERE p.age > 25
RETURN p.name

Follow Relationships

MATCH (a:Person)-[:KNOWS]->(b:Person)
RETURN a.name, b.name

Aggregation Functions

FunctionDescription
COUNT(*)Count rows
COUNT(expr)Count non-null values
COUNT(DISTINCT expr)Count unique values
AVG(expr)Average of numeric values
SUM(expr)Sum of numeric values
MIN(expr)Minimum value
MAX(expr)Maximum value
COLLECT(expr)Collect values into array

Examples

// Count all people
MATCH (p:Person) RETURN COUNT(p) AS total

// Group by city
MATCH (p:Person)
RETURN p.city, COUNT(*) AS cnt
ORDER BY cnt DESC

// Multiple aggregates
MATCH (p:Person)
RETURN MIN(p.age), MAX(p.age), AVG(p.age)

Variable-Length Paths

Match paths of variable length:

// 1 to 3 hops
MATCH (a:Person)-[:KNOWS*1..3]->(b:Person)
RETURN a.name, b.name

// Exactly 2 hops
MATCH (a:Person)-[:KNOWS*2]->(b:Person)
RETURN a.name, b.name

// Up to 5 hops
MATCH (a:Person)-[:KNOWS*..5]->(b:Person)
RETURN a.name, b.name

Named Paths

Capture traversal paths as variables:

MATCH p = (a:Person)-[:KNOWS]->(b:Person)-[:KNOWS]->(c:Person)
RETURN p

Pagination

MATCH (p:Person)
RETURN p.name
ORDER BY p.age DESC
SKIP 0
LIMIT 10

Query Plans

Logical Plan (JSON)

const plan = await engine.getQueryPlan('MATCH (p:Person) RETURN p.name');

Text Tree

const plan = await engine.getQueryPlan(
'MATCH (p:Person)-[:KNOWS]->(b) RETURN p.name, b.name',
undefined,
'text'
);

Mermaid Flowchart

const plan = await engine.getQueryPlan(query, undefined, 'mermaid');

Execution Plans

Use CypherEngineOptions.executionPlan to get the query execution plan with timing and row statistics:

const result = await engine.execute(
'MATCH (p:Person) RETURN p.name AS name',
{},
{ executionPlan: { format: 'text' } }
);
console.log(result.executionPlan);

Example: Complex Query with Execution Plan

For a query like:

MATCH (p:Person|Product)-[r:KNOWS|BOUGHT]->(t:People|Product)-[r2:IN_CATEGORY]->(c:Category)
WHERE r.weight > 5 AND p.score > 90
RETURN p.label AS personLabel,
p.score AS personScore,
avg(t.score) AS avgTargetScore,
sum(r.weight) AS totalWeight,
count(r) AS relationshipCount
ORDER BY personScore DESC

The query plan shows the execution steps:

├— NodeScanStep (p:Person|Product { score > 90 })
├— EdgeExpandStep (→) r:KNOWS|BOUGHT → t:People|Product
├— EdgeExpandStep (→) r2:IN_CATEGORY → c:Category
├— FilterStep r.weight > 5
├— AggregateStep [AVG(avgTargetScore), SUM(totalWeight), COUNT(relationshipCount)]
├— SortStep [personScore DESC]
└— ProjectStep [personLabel, personScore, avgTargetScore, totalWeight, relationshipCount]

The execution plan includes timing, percentage, and row counts:

├— NodeScanStep (p:Person|Product { score > 90 }) (1ms, 3.7%, 390 rows)
├— EdgeExpandStep (→) r:KNOWS|BOUGHT → t:People|Product (21ms, 77.8%, 97 rows)
├— EdgeExpandStep (→) r2:IN_CATEGORY → c:Category (5ms, 18.5%, 15 rows)
├— FilterStep r.weight > 5 (0ms, 0.0%, 15 rows)
├— AggregateStep [AVG(avgTargetScore), SUM(totalWeight), COUNT(relationshipCount)] (0ms, 0.0%, 14 rows)
├— SortStep [personScore DESC] (0ms, 0.0%, 14 rows)
└— ProjectStep [personLabel, personScore, avgTargetScore, totalWeight, relationshipCount] (0ms, 0.0%, 14 rows)

Available Formats

// Text tree with stats (default when executionPlan is set)
{ executionPlan: { format: 'text' } }

// JSON with full statistics
{ executionPlan: { format: 'json' } }

// Mermaid flowchart
{ executionPlan: { format: 'mermaid' } }

Supported Clauses

ClauseSupportNotes
MATCH✅ Read-onlyTyped/untyped nodes, directed edges
WHERE✅ Full expressionsAND/OR/NOT, comparisons, IN, IS NULL
RETURN✅ With DISTINCTProperty access, aliases with AS
ORDER BY✅ ASC/DESCDefault ASC
SKIP✅ Literal + $paramRuntime evaluation
LIMIT✅ Literal + $paramRuntime evaluation
CREATE/DELETE/SET❌ RejectedRead-only engine

Next Steps