Cypher Query Language Guide¶
Complete guide to querying NornicDB with Cypher - the graph query language.
📋 Table of Contents¶
- Introduction
- Basic Syntax
- Creating Data
- Reading Data
- Updating Data
- Deleting Data
- Pattern Matching
- Functions
- Aggregations
- Advanced Queries
- Temporal Snapshot Queries
Introduction¶
Cypher is a declarative graph query language that allows you to express what data you want, not how to get it. It uses ASCII-art syntax to represent graph patterns.
Basic Concepts¶
- Nodes:
(n)- Entities in your graph - Relationships:
-[r]->- Connections between nodes - Labels:
(n:Person)- Types/categories - Properties:
{name: "Alice"}- Key-value data
Basic Syntax¶
Node Syntax¶
() // Anonymous node
(n) // Node with variable
(n:Person) // Node with label
(n:Person:Employee) // Node with multiple labels
(n {name: "Alice"}) // Node with properties
(n:Person {name: "Alice", age: 30}) // Combined
Relationship Syntax¶
--> // Outgoing relationship
<-- // Incoming relationship
-- // Undirected relationship
-[r]-> // Relationship with variable
-[r:KNOWS]-> // Relationship with type
-[r:KNOWS {since: 2020}]-> // With properties
-[r:KNOWS|FOLLOWS]-> // Multiple types
-[*1..3]-> // Variable length (1-3 hops)
Creating Data¶
CREATE - Create Nodes¶
// Single node
CREATE (alice:Person {name: "Alice", age: 30})
RETURN alice
// Multiple nodes
CREATE
(bob:Person {name: "Bob"}),
(carol:Person {name: "Carol"}),
(company:Company {name: "TechCorp"})
RETURN bob, carol, company
CREATE - Create Relationships¶
// Create nodes and relationship together
CREATE (alice:Person {name: "Alice"})-[r:KNOWS {since: 2020}]->(bob:Person {name: "Bob"})
RETURN alice, r, bob
// Connect existing nodes
MATCH
(alice:Person {name: "Alice"}),
(bob:Person {name: "Bob"})
CREATE (alice)-[r:KNOWS]->(bob)
RETURN r
MERGE - Create if Not Exists¶
// Create node if it doesn't exist
MERGE (alice:Person {name: "Alice"})
ON CREATE SET alice.created = timestamp()
ON MATCH SET alice.accessed = timestamp()
RETURN alice
// Create relationship if it doesn't exist
MATCH
(alice:Person {name: "Alice"}),
(bob:Person {name: "Bob"})
MERGE (alice)-[r:KNOWS]->(bob)
ON CREATE SET r.since = timestamp()
RETURN r
Reading Data¶
MATCH - Find Patterns¶
// Find all nodes with label
MATCH (p:Person)
RETURN p
// Find nodes with properties
MATCH (p:Person {name: "Alice"})
RETURN p
// Find relationships
MATCH (p:Person)-[r:KNOWS]->(friend:Person)
RETURN p.name, friend.name
// Find paths
MATCH path = (alice:Person {name: "Alice"})-[:KNOWS*1..3]->(friend)
RETURN path
WHERE - Filter Results¶
// Simple conditions
MATCH (p:Person)
WHERE p.age > 30
RETURN p.name, p.age
// Multiple conditions
MATCH (p:Person)
WHERE p.age > 25 AND p.age < 40
RETURN p
// String matching
MATCH (p:Person)
WHERE p.name STARTS WITH "A"
RETURN p.name
// Regular expressions
MATCH (p:Person)
WHERE p.email =~ ".*@example\\.com"
RETURN p.name, p.email
// NULL checks
MATCH (p:Person)
WHERE p.email IS NOT NULL
RETURN p
// List membership
MATCH (p:Person)
WHERE p.name IN ["Alice", "Bob", "Carol"]
RETURN p
RETURN - Specify Output¶
// Return nodes
MATCH (p:Person)
RETURN p
// Return properties
MATCH (p:Person)
RETURN p.name, p.age
// Return with alias
MATCH (p:Person)
RETURN p.name AS personName, p.age AS personAge
// Return distinct
MATCH (p:Person)
RETURN DISTINCT p.city
// Return with expressions
MATCH (p:Person)
RETURN p.name, p.age, p.age + 10 AS ageIn10Years
ORDER BY - Sort Results¶
// Sort ascending
MATCH (p:Person)
RETURN p.name, p.age
ORDER BY p.age
// Sort descending
MATCH (p:Person)
RETURN p.name, p.age
ORDER BY p.age DESC
// Multiple sort keys
MATCH (p:Person)
RETURN p.name, p.age, p.city
ORDER BY p.city, p.age DESC
LIMIT & SKIP - Pagination¶
// Limit results
MATCH (p:Person)
RETURN p
LIMIT 10
// Skip and limit (pagination)
MATCH (p:Person)
RETURN p
ORDER BY p.name
SKIP 20
LIMIT 10
Temporal Snapshot Queries¶
For historical and temporal reads, use the temporal procedures rather than trying to express MVCC snapshot selection directly in plain MATCH syntax.
CALL db.temporal.asOf(
'Account',
'accountId',
'acct-42',
'valid_from',
'valid_to',
datetime('2026-03-01T00:00:00Z'),
datetime('2026-03-15T12:30:00Z')
) YIELD node
RETURN node
The final optional argument pair is the MVCC snapshot selector:
systemTimesystemSequence
See Historical Reads & MVCC Retention for pruning, retention policy, and maintenance details.
Updating Data¶
SET - Update Properties¶
// Set single property
MATCH (alice:Person {name: "Alice"})
SET alice.age = 31
RETURN alice
// Set multiple properties
MATCH (alice:Person {name: "Alice"})
SET alice.age = 31, alice.city = "San Francisco"
RETURN alice
// Set from map
MATCH (alice:Person {name: "Alice"})
SET alice += {age: 31, city: "San Francisco"}
RETURN alice
// Add label
MATCH (alice:Person {name: "Alice"})
SET alice:Employee
RETURN labels(alice)
// Replace all properties
MATCH (alice:Person {name: "Alice"})
SET alice = {name: "Alice", age: 31}
RETURN alice
REMOVE - Remove Properties/Labels¶
// Remove property
MATCH (alice:Person {name: "Alice"})
REMOVE alice.email
RETURN alice
// Remove label
MATCH (alice:Person {name: "Alice"})
REMOVE alice:Employee
RETURN labels(alice)
Deleting Data¶
DELETE - Remove Nodes/Relationships¶
// Delete relationship
MATCH (alice:Person)-[r:KNOWS]->(bob:Person)
DELETE r
// Delete node (must have no relationships)
MATCH (bob:Person {name: "Bob"})
DELETE bob
// Delete node and relationships
MATCH (bob:Person {name: "Bob"})
DETACH DELETE bob
// Delete all data (⚠️ Use with caution!)
MATCH (n)
DETACH DELETE n
Pattern Matching¶
Simple Patterns¶
// Direct relationship
MATCH (alice:Person)-[:KNOWS]->(friend:Person)
RETURN alice.name, friend.name
// Bidirectional
MATCH (alice:Person)-[:KNOWS]-(friend:Person)
RETURN alice.name, friend.name
// Multiple relationships
MATCH (alice:Person)-[:KNOWS]->(friend)-[:WORKS_AT]->(company:Company)
RETURN alice.name, friend.name, company.name
Variable Length Paths¶
// Friends of friends (2 hops)
MATCH (alice:Person {name: "Alice"})-[:KNOWS*2]-(fof:Person)
RETURN DISTINCT fof.name
// Up to 3 hops
MATCH (alice:Person {name: "Alice"})-[:KNOWS*1..3]-(connected:Person)
RETURN DISTINCT connected.name
// Any length (⚠️ Can be slow!)
MATCH (alice:Person {name: "Alice"})-[:KNOWS*]-(connected:Person)
RETURN DISTINCT connected.name
Shortest Path¶
// Shortest path between two nodes
MATCH path = shortestPath(
(alice:Person {name: "Alice"})-[:KNOWS*]-(dave:Person {name: "Dave"})
)
RETURN path, length(path)
// All shortest paths
MATCH path = allShortestPaths(
(alice:Person {name: "Alice"})-[:KNOWS*]-(dave:Person {name: "Dave"})
)
RETURN path
Optional Patterns¶
// Optional match (like LEFT JOIN)
MATCH (p:Person)
OPTIONAL MATCH (p)-[:WORKS_AT]->(c:Company)
RETURN p.name, c.name
Functions¶
String Functions¶
MATCH (p:Person)
RETURN
toLower(p.name) AS lowercase,
toUpper(p.name) AS uppercase,
substring(p.name, 0, 3) AS first3,
replace(p.name, "Alice", "Alicia") AS replaced,
split(p.email, "@") AS emailParts,
trim(p.name) AS trimmed
Math Functions¶
RETURN
abs(-5) AS absolute,
ceil(3.2) AS ceiling,
floor(3.8) AS floor,
round(3.14159, 2) AS rounded,
sqrt(16) AS squareRoot,
rand() AS random
List Functions¶
RETURN
size([1,2,3,4,5]) AS listSize,
head([1,2,3]) AS first,
tail([1,2,3]) AS rest,
last([1,2,3]) AS lastElement,
range(1, 10) AS numbers
Temporal Functions¶
RETURN
timestamp() AS currentTimestamp,
date() AS currentDate,
datetime() AS currentDateTime,
duration({days: 7}) AS oneWeek
See Cypher Functions Reference for complete list.
Aggregations¶
COUNT¶
// Count nodes
MATCH (p:Person)
RETURN count(p) AS totalPeople
// Count relationships
MATCH ()-[r:KNOWS]->()
RETURN count(r) AS totalFriendships
// Count distinct
MATCH (p:Person)
RETURN count(DISTINCT p.city) AS uniqueCities
SUM, AVG, MIN, MAX¶
MATCH (p:Person)
RETURN
sum(p.age) AS totalAge,
avg(p.age) AS averageAge,
min(p.age) AS youngest,
max(p.age) AS oldest
COLLECT¶
// Collect into list
MATCH (p:Person)
RETURN collect(p.name) AS allNames
// Collect distinct
MATCH (p:Person)
RETURN collect(DISTINCT p.city) AS cities
GROUP BY (Implicit)¶
// Group by city
MATCH (p:Person)
RETURN p.city, count(p) AS peopleInCity
ORDER BY peopleInCity DESC
// Group by multiple fields
MATCH (p:Person)-[:WORKS_AT]->(c:Company)
RETURN c.name, p.city, count(p) AS employees
ORDER BY employees DESC
Advanced Queries¶
WITH - Pipeline Queries¶
// Filter aggregated results
MATCH (p:Person)
WITH p.city AS city, count(p) AS population
WHERE population > 10
RETURN city, population
// Multiple steps
MATCH (p:Person)-[:KNOWS]->(friend:Person)
WITH p, count(friend) AS friendCount
WHERE friendCount > 5
RETURN p.name, friendCount
ORDER BY friendCount DESC
UNWIND - Expand Lists¶
// Expand list into rows
UNWIND [1, 2, 3, 4, 5] AS number
RETURN number * 2 AS doubled
// Create multiple nodes from list
UNWIND ["Alice", "Bob", "Carol"] AS name
CREATE (p:Person {name: name})
RETURN p
CASE - Conditional Logic¶
MATCH (p:Person)
RETURN p.name,
CASE
WHEN p.age < 18 THEN "Minor"
WHEN p.age < 65 THEN "Adult"
ELSE "Senior"
END AS ageGroup
UNION - Combine Results¶
// Union (removes duplicates)
MATCH (p:Person)
RETURN p.name AS name
UNION
MATCH (c:Company)
RETURN c.name AS name
// Union all (keeps duplicates)
MATCH (p:Person)
RETURN p.name AS name
UNION ALL
MATCH (c:Company)
RETURN c.name AS name
Subqueries¶
// Correlated subquery
MATCH (p:Person)
CALL {
WITH p
MATCH (p)-[:KNOWS]->(friend:Person)
RETURN count(friend) AS friendCount
}
RETURN p.name, friendCount
Best Practices¶
1. Use Parameters¶
// Bad: Hardcoded values
MATCH (p:Person {name: "Alice"})
RETURN p
// Good: Use parameters
MATCH (p:Person {name: $name})
RETURN p
2. Create Indexes¶
// Create index for better performance
CREATE INDEX person_name FOR (p:Person) ON (p.name)
CREATE INDEX person_email FOR (p:Person) ON (p.email)
3. Use EXPLAIN/PROFILE¶
// Understand query plan
EXPLAIN MATCH (p:Person) WHERE p.age > 30 RETURN p
// Profile actual execution
PROFILE MATCH (p:Person)-[:KNOWS]->(friend) RETURN p, friend
4. Limit Results¶
5. Use DISTINCT Carefully¶
// DISTINCT can be expensive
MATCH (p:Person)
RETURN DISTINCT p.city
// Better: Use aggregation
MATCH (p:Person)
WITH p.city AS city
RETURN city
⏭️ Next Steps¶
- Cypher Functions Reference - Complete function list
- Graph Traversal - Advanced pattern matching
- Complete Examples - Full applications
- Performance Guide - Query optimization
Need more examples? → Complete Examples
Ready for advanced patterns? → Graph Traversal