Cypher Query Language
GrafitoDB includes a complete Cypher parser and executor, allowing you to use Neo4j-style declarative queries.
What is Cypher?
Cypher is a declarative graph query language that describes patterns in graphs using ASCII-art notation.
Why Use Cypher?
| Approach | Best For |
|---|---|
| Programmatic API | Simple CRUD, dynamic queries |
| Cypher | Complex patterns, analytics, reporting |
Basic Pattern Syntax
Nodes
// Any node
(n)
// Node with label
(p:Person)
// Node with multiple labels
(p:Person:Employee)
// Node with variable and label
(a:Person)
// Anonymous node
(:Person)
Relationships
// Directed relationship
(a)-[:KNOWS]->(b)
// Relationship with properties
(a)-[:KNOWS {since: 2020}]->(b)
// Anonymous relationship
(a)-->(b)
// Bidirectional (matches both directions)
(a)-[:KNOWS]-(b)
Paths
// Two-hop path
(a)-[:KNOWS]->()-[:WORKS_AT]->(c)
// Variable-length path
(a)-[:KNOWS*1..3]->(b)
// Named path
path = (a)-[:KNOWS*]->(b)
Executing Cypher in Grafito
from grafito import GrafitoDatabase
db = GrafitoDatabase(':memory:')
# Execute without results
db.execute("CREATE (n:Person {name: 'Alice'})")
# Execute with results
results = db.execute("MATCH (n:Person) RETURN n.name")
for row in results:
print(row['n.name'])
Query Structure
A typical Cypher query has this structure:
[USE] // Graph selection (not in Grafito)
[READING] // MATCH, OPTIONAL MATCH
[PROJECTING] // WITH
[READING] // Additional MATCH
[WHERE] // Filters
[PROJECTING] // RETURN
[ORDER BY] // Sorting
[SKIP] // Pagination
[LIMIT] // Pagination
Clauses Overview
| Clause | Purpose | Example |
|---|---|---|
MATCH |
Find patterns | MATCH (n:Person) |
CREATE |
Create nodes/relationships | CREATE (n:Person) |
MERGE |
Find or create | MERGE (n:Person {email: 'a@b'}) |
SET |
Update properties | SET n.name = 'Alice' |
DELETE |
Remove nodes/relationships | DELETE n |
REMOVE |
Remove labels/properties | REMOVE n:OldLabel |
RETURN |
Define output | RETURN n.name |
WHERE |
Filter results | WHERE n.age > 25 |
ORDER BY |
Sort results | ORDER BY n.name ASC |
SKIP |
Skip N results | SKIP 10 |
LIMIT |
Limit results | LIMIT 10 |
UNION |
Combine results | ... UNION ... |
CALL |
Execute procedures | CALL db.vector.search(...) |
Quick Examples
Create Data
db.execute("""
CREATE (a:Person {name: 'Alice', age: 30}),
(b:Person {name: 'Bob', age: 25}),
(a)-[:KNOWS {since: 2020}]->(b)
""")
Query Patterns
# Find all persons
results = db.execute("MATCH (n:Person) RETURN n.name")
# Find specific person
results = db.execute("MATCH (n:Person {name: 'Alice'}) RETURN n")
# Find relationships
results = db.execute("""
MATCH (a:Person)-[r:KNOWS]->(b:Person)
RETURN a.name, b.name, r.since
""")
Update Data
# Update property
db.execute("""
MATCH (n:Person {name: 'Alice'})
SET n.age = 31
""")
# Add label
db.execute("""
MATCH (n:Person {name: 'Alice'})
SET n:Employee
""")
# Remove property
db.execute("""
MATCH (n:Person)
REMOVE n.temporary
""")
Delete Data
# Delete relationship
db.execute("""
MATCH (a)-[r:KNOWS]->(b)
WHERE a.name = 'Alice'
DELETE r
""")
# Delete node (and its relationships)
db.execute("""
MATCH (n:Person {name: 'Alice'})
DELETE n
""")
# Delete everything (careful!)
db.execute("MATCH (n) DETACH DELETE n")
Variable-Length Paths
Configure default max hops when creating the database:
db = GrafitoDatabase(':memory:', cypher_max_hops=5)
# Unbounded uses default max
db.execute("MATCH (a)-[:KNOWS*..]->(b) RETURN b")
# Explicit bounds
db.execute("MATCH (a)-[:KNOWS*1..3]->(b) RETURN b")
Result Format
Query results are returned as a list of dictionaries:
results = db.execute("""
MATCH (n:Person)
RETURN n.name, n.age
""")
for row in results:
print(f"Name: {row['n.name']}")
print(f"Age: {row['n.age']}")
With aliases:
results = db.execute("""
MATCH (n:Person)
RETURN n.name AS name, n.age AS age
""")
for row in results:
print(f"{row['name']}: {row['age']}")
Hybrid Usage
Mix Cypher with the programmatic API:
# Create with API
alice = db.create_node(labels=['Person'], properties={'name': 'Alice'})
# Query with Cypher
results = db.execute("MATCH (n:Person) RETURN n")
# Update with Cypher
db.execute(f"MATCH (n) WHERE id(n) = {alice.id} SET n.active = true")
# Verify with API
updated = db.get_node(alice.id)
print(updated.properties['active']) # True