Cypher Reference
Advanced: this reference assumes basic Python and database-query concepts.
For guided first use, start with Your first graph. Each Cypher
example below is a separate statement; copy one into forge.execute() using a
graph with the labels and properties shown.
GraphForge executes openCypher through its Rust core. Run
queries through forge.execute(query, params=None) — every call returns a
PyArrow Table (no CypherValue wrappers).
This guide covers everyday clauses, patterns, expressions, and functions. For install and first-graph steps, start with Quick Start; for programmatic construction, see Graph Construction.
Compliance: See TCK Compliance for the current openCypher TCK corpus gate.
Table of Contents
Section titled “Table of Contents”- Reading Data
- Writing Data
- Updating Data
- Query Chaining
- Patterns
- Expressions and Operators
- Functions
- Temporal Types
- Parameters
- Saved Queries
Saved Queries
Section titled “Saved Queries”A Project can keep named, reusable read-only analyses. Each definition has a
stable query_uuid, a unique case-sensitive name without surrounding whitespace,
an optional description, Cypher text, and parameter declarations. These are native
Project metadata, so they survive reopen and complete portable export/import.
Creating or changing this metadata requires admitted storage. Use a new project
on supported durable storage for this example;
do not assume the memory-only quickstart removes this requirement. In particular,
an in-memory instance whose temporary directory is on an unsupported filesystem
can query the graph but fail when saving a query definition.
from pathlib import Pathfrom uuid import uuid4from graphforge import GraphForge
Path("saved-query-project").mkdir()forge = GraphForge("saved-query-project")forge.execute("CREATE (:Person {age:20}), (:Person {age:40})")query_uuid = str(uuid4())forge.create_saved_query({ "query_uuid": query_uuid, "name": "People above an age", "description": "Count people meeting a supplied threshold", "query": "MATCH (p:Person) WHERE p.age >= $minimum RETURN count(p) AS people", "parameters": {"minimum": "integer"},})definitions = forge.saved_queries()definition = forge.saved_query(query_uuid)table = forge.execute_saved_query(query_uuid, {"minimum": 30})assert table.to_pylist() == [{"people": 1}]forge.update_saved_query({**definition, "name": "People by age threshold"})forge.delete_saved_query(query_uuid)forge.close()Parameter declarations must exactly name the $parameters referenced by the
query. Every declared value is required on execution and must match its type:
boolean, integer (signed 64-bit), float (finite), string, or uuid.
Null, defaults, and undeclared values are refused. Python UUID parameters use
uuid.UUID; Node and CLI use {"$uuid": "<canonical UUID>"}. Literal values
embedded in query text are part of the published definition; supply private
values through execution parameters instead.
Node and CLI JSON numbers are interpreted by the saved declaration: an integral
number can supply float, and a floating representation can supply integer
only when integral and within ±9,007,199,254,740,991. Rust and Python retain their
native integer/float distinction. Lean Rust builds support current saved queries;
historical sources require the research feature and otherwise return
GF_CAPABILITY_DISABLED.
Saving validates syntax and the read-only contract without binding to the graph
or running the query. Mutation clauses and procedure CALL are refused. General
aggregates and tables are supported; a saved query need not return membership
UUIDs. If it does return node_uuid or edge_uuid, its text can also be used by
a Slice query selector. A saved definition and a frozen Slice remain separate
objects.
Execution pins one committed generation, uses the instance’s native resource
policy, and collects at most 1,000,000 rows and 64 MiB of Arrow array data.
Exceeding either ceiling fails without a partial result. Supply a
CancellationToken through Python’s cancellation argument, or pass an
AbortSignal as Node’s fourth executeSavedQuery(uuid, params, source, signal)
argument.
Retained research Versions keep the definition revision they captured. Python’s
saved_query, saved_queries, and execute_saved_query accept
source={"kind": "version", "version_uuid": "<UUID>"} to read that revision
and execute against its exact retained graph. Omit source for current state.
A missing/released Version fails; it never follows the live parent. A definition
alone does not retain graph data or promise identical results across projects.
Node exposes createSavedQuery, updateSavedQuery, deleteSavedQuery,
savedQuery, savedQueries, and asynchronous executeSavedQuery; execution
returns Arrow IPC bytes. Rust exposes the same lifecycle plus
saved_query_at/saved_queries_at with SavedQuerySource.
CLI definitions and parameter values use separate JSON files:
gf --project ./research saved-query save --file definition.jsongf --project ./research saved-query listgf --project ./research saved-query show QUERY_UUIDgf --project ./research saved-query update --file definition.jsongf --project ./research saved-query run QUERY_UUID --params parameters.json > result.arrowgf --project ./research saved-query delete QUERY_UUIDlist, show, and run accept --version-uuid UUID. Lifecycle output is JSON;
execution emits Arrow IPC, or JSON with the global --json option. Saving,
listing, publishing, cloning, and importing never execute definitions. Previous
execution values and results are not saved with them.
Reading Data
Section titled “Reading Data”Find nodes and relationships matching a pattern.
// All nodesMATCH (n) RETURN n
// Nodes with labelMATCH (p:Person) RETURN p
// Nodes with multiple labelsMATCH (e:Person:Employee) RETURN e
// Nodes with property filterMATCH (p:Person {name: 'Alice'}) RETURN p
// Directed relationshipMATCH (a:Person)-[:KNOWS]->(b:Person) RETURN a, b
// Undirected relationshipMATCH (a:Person)-[:KNOWS]-(b:Person) RETURN a, b
// Multiple relationship typesMATCH (a)-[r:KNOWS|LIKES]->(b) RETURN a, r, b
// Variable-length pathsMATCH (a:Person)-[:KNOWS*1..3]->(b:Person) RETURN a, b
// Unbounded variable-lengthMATCH (a)-[*]->(b) RETURN a, b
// Named pathMATCH p = (a:Person)-[:KNOWS*]->(b:Person) RETURN p
// Multi-hopMATCH (a:Person)-[:KNOWS]->(b:Person)-[:WORKS_AT]->(c:Company)RETURN a.name, b.name, c.nameOPTIONAL MATCH
Section titled “OPTIONAL MATCH”Left-outer-join semantics: returns NULL for missing matches.
MATCH (p:Person)OPTIONAL MATCH (p)-[:KNOWS]->(friend:Person)RETURN p.name AS person, friend.name AS friend // friend.name is NULL if no match
// Multiple optional matchesMATCH (p:Person)OPTIONAL MATCH (p)-[:WORKS_AT]->(company:Company)OPTIONAL MATCH (p)-[:LIVES_IN]->(city:City)RETURN p.name, company.name, city.nameFilter by any boolean expression.
// ComparisonMATCH (p:Person) WHERE p.age > 25 RETURN p
// NULL checkMATCH (p:Person) WHERE p.email IS NULL RETURN pMATCH (p:Person) WHERE p.email IS NOT NULL RETURN p
// Boolean operatorsMATCH (p:Person) WHERE p.age > 25 AND p.city = 'NYC' RETURN pMATCH (p:Person) WHERE p.age < 20 OR p.age > 60 RETURN pMATCH (p:Person) WHERE NOT p.active RETURN p
// Label predicateMATCH (n) WHERE n:Person RETURN n
// String predicatesMATCH (p:Person) WHERE p.name STARTS WITH 'Al' RETURN pMATCH (p:Person) WHERE p.name ENDS WITH 'ice' RETURN pMATCH (p:Person) WHERE p.name CONTAINS 'lic' RETURN p
// RegexMATCH (p:Person) WHERE p.name =~ 'A.*' RETURN p
// List membershipMATCH (p:Person) WHERE p.city IN ['NYC', 'Boston', 'London'] RETURN p
// Pattern predicate (not returning path)MATCH (p:Person) WHERE (p)-[:KNOWS]->(:Person {name: 'Alice'}) RETURN pMATCH (p:Person) WHERE NOT (p)-[:KNOWS]->() RETURN p
// EXISTS subquery (pattern form)MATCH (p:Person)WHERE EXISTS { (p)-[:KNOWS]->(:Person) }RETURN p.nameRETURN
Section titled “RETURN”Project variables, properties, expressions, and aggregations.
// Return variableMATCH (p:Person) RETURN p
// Return propertyMATCH (p:Person) RETURN p.name, p.age
// AliasMATCH (p:Person) RETURN p.name AS person, p.age AS age
// DISTINCTMATCH (p:Person) RETURN DISTINCT p.city
// Aggregation (implicit GROUP BY on non-aggregated columns)MATCH (p:Person) RETURN p.city AS city, count(*) AS total
// All properties (map)MATCH (p:Person) RETURN properties(p) AS props
// Arithmetic in returnMATCH (p:Person) RETURN p.name, p.salary * 1.1 AS after_raise
// CASE expressionMATCH (p:Person)RETURN p.name, CASE WHEN p.age < 18 THEN 'Minor' WHEN p.age < 65 THEN 'Adult' ELSE 'Senior' END AS category
// Return * (all variables in scope)MATCH (a:Person)-[:KNOWS]->(b:Person) RETURN *ORDER BY, LIMIT, SKIP
Section titled “ORDER BY, LIMIT, SKIP”// Sort ascending (default)MATCH (p:Person) RETURN p.name ORDER BY p.age
// Sort descendingMATCH (p:Person) RETURN p.name ORDER BY p.age DESC
// Multiple sort keysMATCH (p:Person) RETURN p.name ORDER BY p.city ASC, p.age DESC
// Limit resultsMATCH (p:Person) RETURN p.name ORDER BY p.age LIMIT 10
// PaginationMATCH (p:Person) RETURN p.name ORDER BY p.name SKIP 20 LIMIT 10Writing Data
Section titled “Writing Data”CREATE
Section titled “CREATE”Create nodes and relationships.
// Single nodeCREATE (p:Person {name: 'Alice', age: 30})
// Multiple labelsCREATE (e:Person:Employee {name: 'Charlie'})
// Multiple nodes in one clauseCREATE (a:Person {name: 'Alice'}), (b:Person {name: 'Bob'})
// Relationship between existing nodesMATCH (a:Person {name: 'Alice'}), (b:Person {name: 'Bob'})CREATE (a)-[:KNOWS {since: 2020}]->(b)
// Create inlineCREATE (a:Person {name: 'Alice'})-[:KNOWS]->(b:Person {name: 'Bob'})
// CREATE ... RETURNCREATE (p:Person {name: 'Alice'})RETURN p.name AS name, p.node_uuid AS node_uuidFind or create — safe for idempotent upserts within the shipped Rust subset (implementation status).
Supported:
- Standalone new-node MERGE:
MERGE (p:Person {email: '…'}) - Relationship MERGE when both endpoints are already bound:
MATCH (a), (b) MERGE (a)-[:KNOWS]->(b) ON CREATE SET/ON MATCH SETproperty (and label) actions when every row takes the same create-or-match branch
Not supported (structured plan errors):
- Multi-node / relationship-construction MERGE such as
MERGE (a:A)-[:R]->(b:B)→relationship and multi-node MERGE execution is not implemented yet - Row-conditional map actions (
+=/=) when some rows create and others match →row-conditional MERGE map actions are not implemented yet
// Merge node (create if not exists, match if exists)MERGE (p:Person {email: 'alice@example.com'})
// ON CREATE and ON MATCH callbacksMERGE (p:Person {email: 'alice@example.com'})ON CREATE SET p.created = 2024, p.name = 'Alice'ON MATCH SET p.last_seen = 2024
// Merge relationship (both endpoints must already exist)MATCH (a:Person {name: 'Alice'}), (b:Person {name: 'Bob'})MERGE (a)-[:KNOWS]->(b)
// Merge with RETURNMERGE (p:Person {email: 'alice@example.com'})RETURN pUNWIND
Section titled “UNWIND”Expand a list into rows.
UNWIND [1, 2, 3] AS x RETURN x * 2 AS doubled
// Common pattern: batch-create from listUNWIND ['Alice', 'Bob', 'Charlie'] AS nameCREATE (:Person {name: name})
// Expand collected listMATCH (p:Person)WITH collect(p.name) AS namesUNWIND names AS nameRETURN nameUpdating Data
Section titled “Updating Data”Add or update properties and labels.
// Set propertyMATCH (p:Person {name: 'Alice'}) SET p.age = 31
// Multiple propertiesMATCH (p:Person {name: 'Alice'})SET p.age = 31, p.city = 'Boston', p.active = true
// Set from mapMATCH (p:Person {name: 'Alice'})SET p += {age: 31, city: 'Boston'}
// Overwrite all propertiesMATCH (p:Person {name: 'Alice'})SET p = {name: 'Alice', age: 31}
// Add labelMATCH (p:Person {name: 'Alice'}) SET p:Manager
// SET ... RETURNMATCH (p:Person {name: 'Alice'})SET p.age = 31RETURN p.name AS name, p.age AS new_ageREMOVE
Section titled “REMOVE”Remove properties and labels.
// Remove propertyMATCH (p:Person {name: 'Alice'}) REMOVE p.temp
// Remove multipleMATCH (p:Person {name: 'Alice'}) REMOVE p.temp, p.draft
// Remove labelMATCH (p:Person {name: 'Alice'}) REMOVE p:ManagerDELETE / DETACH DELETE
Section titled “DELETE / DETACH DELETE”// Delete a relationshipMATCH (a)-[r:KNOWS]->(b) WHERE a.name = 'Alice' DELETE r
// Delete a node (no relationships may exist)MATCH (p:Person {name: 'Alice'}) DELETE p
// DETACH DELETE: remove node and all its relationshipsMATCH (p:Person {name: 'Alice'}) DETACH DELETE p
// Delete everythingMATCH (n) DETACH DELETE nQuery Chaining
Section titled “Query Chaining”Pass results between query stages, filter aggregations, limit scope.
// Chain match with filterMATCH (p:Person)-[:KNOWS]->(friend)WITH p, count(friend) AS friendsWHERE friends > 5RETURN p.name AS person, friends
// Rename and continueMATCH (p:Person)WITH p.name AS name, p.age AS ageWHERE age > 25RETURN name, age
// Aggregate then matchMATCH (p:Person)WITH p.city AS town, count(*) AS popWHERE pop > 100MATCH (p2:Person)WHERE p2.city = townRETURN p2.name, town, popORDER BY pop DESC
// WITH DISTINCTMATCH (p:Person)-[:KNOWS]->(friend:Person)WITH DISTINCT friendRETURN friend.name AS mutual_friendUNION / UNION ALL
Section titled “UNION / UNION ALL”// UNION (removes duplicates)MATCH (p:Person) RETURN p.name AS nameUNIONMATCH (c:Company) RETURN c.name AS name
// UNION ALL (keeps duplicates)MATCH (p:Person) RETURN p.name AS nameUNION ALLMATCH (p2:Person) RETURN p2.name AS namePatterns
Section titled “Patterns”Node Patterns
Section titled “Node Patterns”| Pattern | Meaning |
|---|---|
(n) |
Any node |
(n:Person) |
Node with label Person |
(n:Person:Employee) |
Node with both labels |
(n:Person {age: 30}) |
Node with label and property |
(:Person) |
Anonymous node with label |
({name: 'Alice'}) |
Anonymous node with property |
Relationship Patterns
Section titled “Relationship Patterns”| Pattern | Meaning |
|---|---|
-[r]-> |
Any directed relationship |
-[:KNOWS]-> |
Specific type |
-[r:KNOWS {since: 2020}]-> |
Type with property |
-[:KNOWS|LIKES]-> |
Multiple types (OR) |
-[*]-> |
Variable-length (any) |
-[*2]-> |
Exactly 2 hops |
-[*1..3]-> |
1 to 3 hops |
-[*..5]-> |
Up to 5 hops |
-[*3..]-> |
3 or more hops |
Path Variables
Section titled “Path Variables”// Bind path to variableMATCH p = (a:Person)-[:KNOWS*]->(b:Person)RETURN length(p) AS hops, nodes(p) AS path_nodesExpressions and Operators
Section titled “Expressions and Operators”Arithmetic
Section titled “Arithmetic”RETURN 5 + 3 // 8RETURN 5 - 3 // 2RETURN 5 * 3 // 15RETURN 5 / 2 // 2 (integer division)RETURN 5.0 / 2 // 2.5RETURN 5 % 2 // 1RETURN 2 ^ 10 // 1024.0Comparison
Section titled “Comparison”RETURN 5 = 5 // trueRETURN 5 <> 6 // trueRETURN 5 < 6 // trueRETURN 5 <= 5 // trueRETURN 6 > 5 // trueRETURN 6 >= 6 // trueBoolean
Section titled “Boolean”RETURN true AND false // falseRETURN true OR false // trueRETURN NOT true // falseRETURN true XOR true // false
// NULL propagationRETURN null AND true // nullRETURN null OR true // trueRETURN NOT null // nullString
Section titled “String”RETURN 'hello' + ' world' // 'hello world'RETURN 'Alice' STARTS WITH 'Al' // trueRETURN 'Alice' ENDS WITH 'ice' // trueRETURN 'Alice' CONTAINS 'lic' // trueRETURN 'Alice' =~ 'A.*' // true (regex)List Operators
Section titled “List Operators”RETURN [1, 2, 3] + [4, 5] // [1, 2, 3, 4, 5]RETURN 3 IN [1, 2, 3] // trueRETURN [1, 2, 3][0] // 1RETURN [1, 2, 3][1..3] // [2, 3]// NULL propagates through most operationsRETURN null + 5 // nullRETURN null = null // null (use IS NULL instead)
// Safe operatorsMATCH (p:Person) WHERE p.age IS NULL RETURN pMATCH (p:Person) WHERE p.age IS NOT NULL RETURN pCASE Expression
Section titled “CASE Expression”// Simple formMATCH (p:Person)RETURN CASE p.status WHEN 'active' THEN 'Active User' WHEN 'inactive' THEN 'Inactive User' ELSE 'Unknown'END
// Generic formMATCH (p:Person)RETURN CASE WHEN p.age < 18 THEN 'Minor' WHEN p.age < 65 THEN 'Adult' ELSE 'Senior'ENDFunctions
Section titled “Functions”String Functions
Section titled “String Functions”| Function | Example | Result |
|---|---|---|
toLower(s) |
toLower('HELLO') |
'hello' |
toUpper(s) |
toUpper('hello') |
'HELLO' |
trim(s) |
trim(' hi ') |
'hi' |
ltrim(s) |
ltrim(' hi') |
'hi' |
rtrim(s) |
rtrim('hi ') |
'hi' |
replace(s, f, r) |
replace('aaa', 'a', 'b') |
'bbb' |
substring(s, start, len) |
substring('hello', 1, 3) |
'ell' |
split(s, delim) |
split('a,b,c', ',') |
['a','b','c'] |
reverse(s) |
reverse('hello') |
'olleh' |
size(s) |
size('hello') |
5 |
toString(x) |
toString(42) |
'42' |
Math Functions
Section titled “Math Functions”| Function | Description |
|---|---|
abs(n) |
Absolute value |
ceil(n) |
Round up |
floor(n) |
Round down |
round(n) |
Round to nearest |
sqrt(n) |
Square root |
power(base, exp) |
Power |
exp(n) |
e^n |
log(base, n) |
Logarithm of n to the given base |
rand() |
Random 0.0–1.0 |
sign(n) |
-1, 0, or 1 |
List Functions
Section titled “List Functions”| Function | Example | Result |
|---|---|---|
head(list) |
head([1,2,3]) |
1 |
tail(list) |
tail([1,2,3]) |
[2,3] |
last(list) |
last([1,2,3]) |
3 |
size(list) |
size([1,2,3]) |
3 |
range(start, end) |
range(1,5) |
[1,2,3,4,5] |
range(start, end, step) |
range(0,10,2) |
[0,2,4,6,8,10] |
reverse(list) |
reverse([1,2,3]) |
[3,2,1] |
keys(map) |
keys({a:1,b:2}) |
['a','b'] |
List Comprehension and Predicates
Section titled “List Comprehension and Predicates”// Filter a listRETURN [x IN range(1,10) WHERE x % 2 = 0] // [2,4,6,8,10]
// Transform a listRETURN [x IN range(1,5) | x * x] // [1,4,9,16,25]
// Filter + transformRETURN [x IN range(1,10) WHERE x > 5 | x * 2] // [12,14,16,18,20]
// all() — every element satisfies predicateRETURN all(x IN [2,4,6] WHERE x % 2 = 0) // true
// any() — at least one element satisfies predicateRETURN any(x IN [1,2,3] WHERE x > 2) // true
// none() — no element satisfies predicateRETURN none(x IN [1,2,3] WHERE x > 5) // true
// single() — exactly one element satisfies predicateRETURN single(x IN [1,2,3] WHERE x = 2) // trueAggregation Functions
Section titled “Aggregation Functions”// Count rowsMATCH (p:Person) RETURN count(*) AS total
// Count non-nullMATCH (p:Person) RETURN count(p.age) AS with_age
// Count distinctMATCH (p:Person) RETURN count(DISTINCT p.city) AS cities
// Numeric aggregationsMATCH (p:Person) RETURN sum(p.salary), avg(p.age), min(p.age), max(p.age)
// Collect into listMATCH (p:Person) RETURN collect(p.name) AS names
// Collect distinctMATCH (p:Person) RETURN collect(DISTINCT p.city) AS cities
// PercentileMATCH (p:Person) RETURN percentileDisc(p.age, 0.5) AS medianGraph Functions
Section titled “Graph Functions”// Node identity (UUID, not a numeric storage ID)MATCH (n:Person) RETURN n.node_uuid
// LabelsMATCH (n:Person) RETURN labels(n) // list of labelsMATCH (n:Person) RETURN 'Person' IN labels(n) // true/false
// Relationship typeMATCH ()-[r]->() RETURN type(r)
// Properties (as map)MATCH (n:Person) RETURN properties(n)
// Keys (property names)MATCH (n:Person) RETURN keys(n)
// Path functionsMATCH p = (a)-[*]->(b)RETURN nodes(p), relationships(p), length(p)
// EndpointsMATCH (a)-[r]->(b)RETURN startNode(r), endNode(r)
// Degree (count outgoing relationships)MATCH (n:Person {name: 'Alice'})-[:KNOWS]->(other)RETURN count(other) AS out_degreePredicate Functions
Section titled “Predicate Functions”// Property exists (use IS NOT NULL)MATCH (p:Person) WHERE p.email IS NOT NULL RETURN p
// Empty lists and strings; unknown is separate from emptyRETURN size([]) = 0 // trueRETURN size('') = 0 // trueRETURN size(null) = 0 // null
// Null coalescingRETURN coalesce(null, null, 'default') // 'default'MATCH (p:Person) RETURN coalesce(p.nickname, p.name) // first non-nullConversion Functions
Section titled “Conversion Functions”RETURN toInteger('42') // 42RETURN toInteger(3.7) // 3RETURN toFloat('3.14') // 3.14RETURN toString(42) // '42'RETURN toBoolean('true') // trueRETURN toBoolean('false') // falsetoBoolean() accepts booleans and strings (or null), not numeric values.
For a numeric coding rule, state it explicitly, for example RETURN 0 <> 0.
Temporal Types
Section titled “Temporal Types”GraphForge implements full openCypher temporal precision including nanoseconds and IANA timezone names.
Construction
Section titled “Construction”RETURN date('2024-01-15')RETURN date({year: 2024, month: 1, day: 15})RETURN date() // current date
RETURN time('14:30:00.000000789') // with nanosecondsRETURN time({hour: 14, minute: 30, second: 0, nanosecond: 789})
RETURN datetime('2024-01-15T14:30:00[Europe/London]') // IANA timezoneRETURN datetime('2024-01-15T14:30:00+01:00') // offsetRETURN datetime() // current datetime
RETURN localdatetime('2024-01-15T14:30:00')RETURN duration('P1Y2M3DT4H5M6.789S')RETURN duration({years: 1, months: 2, days: 3})Accessors
Section titled “Accessors”RETURN date('2024-01-15').year // 2024RETURN date('2024-01-15').month // 1RETURN date('2024-01-15').day // 15RETURN date('2024-01-15').week // 3 (ISO week)RETURN date('2024-01-15').ordinalDay // 15
RETURN time('14:30:00.000000789').hour // 14RETURN time('14:30:00.000000789').nanosecond // 789
RETURN datetime('2024-01-15T14:30:00[Europe/Stockholm]').timezone// 'Europe/Stockholm'
RETURN duration('P1Y2M3DT4H5M6S').years // 1RETURN duration('P1Y2M3DT4H5M6S').months // 2RETURN duration('PT0.000000789S').nanoseconds // 789Arithmetic
Section titled “Arithmetic”RETURN date('2024-01-01') + duration('P1M') // 2024-02-01RETURN date('2024-01-01') - duration('P1Y') // 2023-01-01RETURN duration('P1Y') + duration('P6M') // P1Y6M
// BetweenRETURN duration.between(date('2020-01-01'), date('2024-01-01'))RETURN duration.inMonths(date('2020-01-01'), date('2024-01-01'))RETURN duration.inDays(datetime('2020-01-01T00:00Z'), datetime('2020-01-15T12:00Z'))RETURN duration.inSeconds(time('08:00'), time('16:30'))Extreme Years
Section titled “Extreme Years”GraphForge supports years outside Python’s native range (1–9999):
RETURN localdatetime('+999999999-12-31T23:59:59').year // 999999999RETURN localdatetime('-000001-01-01T00:00').year // -1Truncation
Section titled “Truncation”RETURN date.truncate('month', date('2024-07-15')) // 2024-07-01RETURN datetime.truncate('day', datetime()) // current day at midnightRETURN time.truncate('hour', time('14:37:00')) // 14:00:00Parameters
Section titled “Parameters”Bind values as parameters to avoid string interpolation:
# Pythontable = forge.execute( "MATCH (p:Person {name: $name}) WHERE p.age > $min_age RETURN p", {"name": "Alice", "min_age": 25},)// In Cypher, $name and $min_age are the parameter syntaxMATCH (p:Person {name: $name})WHERE p.age > $min_ageRETURN p.name, p.ageParameters work with all value types: strings, integers, floats, booleans, null, lists, maps.
Common Patterns
Section titled “Common Patterns”Find Friends-of-Friends
Section titled “Find Friends-of-Friends”MATCH (me:Person {name: 'Alice'})-[:KNOWS]->(friend)-[:KNOWS]->(foaf:Person)WHERE NOT (me)-[:KNOWS]->(foaf) AND me <> foafRETURN DISTINCT foaf.name AS recommendationMost Connected Nodes
Section titled “Most Connected Nodes”MATCH (p:Person)-[:KNOWS]->(friend)RETURN p.name AS person, count(friend) AS connectionsORDER BY connections DESCLIMIT 10Upsert Pattern
Section titled “Upsert Pattern”MERGE (p:Person {email: 'alice@example.com'})ON CREATE SET p.name = 'Alice', p.created = 2024ON MATCH SET p.last_seen = 2024RETURN pBatch Create from List
Section titled “Batch Create from List”UNWIND [ {name: 'Alice', age: 30}, {name: 'Bob', age: 25}, {name: 'Carol', age: 35}] AS rowCREATE (:Person {name: row.name, age: row.age})Conditional Return
Section titled “Conditional Return”MATCH (p:Person)RETURN p.name, CASE WHEN p.age IS NULL THEN 'unknown' WHEN p.age < 18 THEN 'minor' ELSE 'adult' END AS categoryEXISTS Subquery
Section titled “EXISTS Subquery”// Nodes that have at least one outgoing relationshipMATCH (p:Person)WHERE EXISTS { (p)-[:KNOWS]->() }RETURN p.name
// Nodes that have no relationshipsMATCH (p:Person)WHERE NOT (p)-[]-()RETURN p.name AS isolatedSee Also
Section titled “See Also”- Graph Construction — Python API for building graphs
- Quick Start — five-minute walkthrough
- OpenCypher Compatibility — feature matrix
- TCK Compliance — Rust engine conformance status