Expressions¶
GQL supports a rich expression language for conditional logic, type conversion, subqueries and list operations.
CASE Expressions¶
Searched CASE¶
Evaluate conditions in order and return the first matching result:
MATCH (p:Person)
RETURN p.name,
CASE
WHEN p.age < 18 THEN 'minor'
WHEN p.age < 65 THEN 'adult'
ELSE 'senior'
END AS category
Simple CASE¶
Compare an expression against specific values:
MATCH (p:Person)
RETURN p.name,
CASE p.status
WHEN 'A' THEN 'Active'
WHEN 'I' THEN 'Inactive'
WHEN 'P' THEN 'Pending'
ELSE 'Unknown'
END AS status_label
NULLIF¶
Returns null if both arguments are equal, otherwise returns the first argument. Useful for avoiding division by zero:
COALESCE¶
Returns the first non-null value from the argument list:
-- Display name fallback chain
MATCH (p:Person)
RETURN COALESCE(p.nickname, p.firstName, p.email) AS display_name
CAST¶
Convert a value to a different type with CAST(expr AS type):
-- Numeric conversions
RETURN CAST('42' AS INT) -- 42
RETURN CAST(42 AS FLOAT) -- 42.0
RETURN CAST(42 AS STRING) -- '42'
RETURN CAST('true' AS BOOLEAN) -- true
-- Temporal conversions
RETURN CAST('2024-01-15' AS DATE)
RETURN CAST('14:30:00' AS TIME)
RETURN CAST('2024-01-15T14:30:00Z' AS DATETIME)
RETURN CAST('P1Y2M' AS DURATION)
-- Zoned temporal conversions
RETURN CAST('2024-01-15T14:30:00+05:30' AS ZONED DATETIME)
RETURN CAST('14:30:00+05:30' AS ZONED TIME)
-- Wrap a scalar in a list
RETURN CAST(42 AS LIST) -- [42]
Supported target types: INT/INTEGER, FLOAT, STRING, BOOLEAN, DATE, TIME, DATETIME, DURATION, ZONED DATETIME, ZONED TIME, LIST.
Dynamic Parameters¶
Use $param placeholders in queries and provide values from the host language:
// Node.js
const result = await db.execute(
"MATCH (p:Person) WHERE p.name = $name RETURN p",
{ name: "Alix" }
);
LET ... IN ... END¶
Bind local variables within an expression. The variables are scoped to the expression only.
MATCH (p:Person)
RETURN p.name,
LET base = p.salary,
bonus = base * 0.1
IN base + bonus
END AS total_compensation
List Comprehensions¶
Transform and filter lists in a single expression:
-- Filter: keep only even numbers
RETURN [x IN [1, 2, 3, 4, 5] WHERE x % 2 = 0] AS evens
-- [2, 4]
-- Transform: double each value
RETURN [x IN [1, 2, 3] | x * 2] AS doubled
-- [2, 4, 6]
-- Filter and transform
RETURN [x IN [1, 2, 3, 4, 5] WHERE x > 2 | x * 10] AS result
-- [30, 40, 50]
-- With graph data
MATCH (p:Person)-[:KNOWS]->(friend)
RETURN p.name,
[f IN collect(friend) WHERE f.age > 30 | f.name] AS older_friends
List Predicates¶
Test whether list elements satisfy a condition:
-- all(): every element must match
RETURN all(x IN [2, 4, 6] WHERE x % 2 = 0) -- true
-- any(): at least one element must match
RETURN any(x IN [1, 2, 3] WHERE x > 2) -- true
-- none(): no element must match
RETURN none(x IN [1, 2, 3] WHERE x > 5) -- true
-- single(): exactly one element must match
RETURN single(x IN [1, 2, 3] WHERE x = 2) -- true
-- Practical example: check path properties
MATCH path = (a:Person)-[:KNOWS*]->(b:Person)
WHERE a.name = 'Alix'
AND all(n IN nodes(path) WHERE n.active = true)
RETURN path
reduce()¶
Fold a list into a single value using an accumulator:
-- Sum a list
RETURN reduce(acc = 0, x IN [1, 2, 3, 4, 5] | acc + x) AS total
-- 15
-- Build a string
RETURN reduce(s = '', name IN ['Alix', 'Gus', 'Harm'] | s + name + ', ') AS names
-- Compute from graph data
MATCH (p:Person)
WITH collect(p.salary) AS salaries
RETURN reduce(total = 0, s IN salaries | total + s) AS payroll
Subquery Expressions¶
EXISTS¶
Check whether a pattern or subquery has any results:
-- Pattern exists
MATCH (p:Person)
WHERE EXISTS { MATCH (p)-[:MANAGES]->(:Team) }
RETURN p.name AS manager
-- Subquery with filtering
MATCH (p:Person)
WHERE EXISTS {
MATCH (p)-[:ORDERED]->(o:Order)
WHERE o.total > 1000
}
RETURN p.name AS high_value_customer
COUNT¶
Count the number of results from a subquery:
VALUE¶
Return a single scalar value from a subquery:
MATCH (p:Person)
RETURN p.name,
VALUE {
MATCH (p)-[:KNOWS]->(friend)
RETURN count(friend)
} AS friend_count
Index Access¶
Access list elements by index (0-based):
RETURN [10, 20, 30, 40][0] -- 10
RETURN [10, 20, 30, 40][2] -- 30
-- With graph data
MATCH (p:Person)
RETURN p.tags[0] AS first_tag
Map Literals¶
Create and access map (dictionary) values:
-- Map literal
RETURN {name: 'Alix', age: 30, active: true} AS person
-- Access map properties
WITH {name: 'Alix', age: 30} AS person
RETURN person.name, person.age
-- Maps in mutations
MATCH (p:Person {name: 'Alix'})
SET p += {city: 'NYC', role: 'engineer'}
SESSION_USER¶
Returns the current session user name. In embedded databases, this returns 'default'.