Docs
View as markdown

Expressions

Operator precedence, comparison and null rules, string, list and map operators, CASE, comprehensions, map projections, reduce, list and type predicates.

cypher

An expression computes one value from literals, variables, property A named value stored on a node or relationship, such as name: 'Ada'; values are scalars, temporal and spatial values, vectors, or lists of them. Read more in the glossary, parameter A named value a statement refers to as $name and the caller binds separately, such as with --param name=value on the CLI. Read more in the glossary, operators, and function calls. relate evaluates expressions in RETURN, WITH, WHERE, SET, ORDER BY and anywhere else a clause takes a value. The cells on this page run on relate's WebAssembly (WASM) build; the CLI and the clients evaluate expressions with the same engine.

Synopsis

<literal> | <variable> | $<parameter>
<expression>.<key> | <expression>[<index or key>] | <list>[<from>..<to>]
<unary operator> <expression> | <expression> <binary operator> <expression>
<function>(<argument>, …)
CASE … WHEN … THEN … [ELSE …] END
[<variable> IN <list> [WHERE <predicate>] [| <expression>]]
[<pattern> [WHERE <predicate>] | <expression>]
<variable> {.<key>, .*, <key>: <expression>, …}
reduce(<accumulator> = <initial>, <variable> IN <list> | <expression>)
all | any | none | single (<variable> IN <list> WHERE <predicate>)
<expression> IS [NOT] :: <type>
COUNT { … } | EXISTS { … } | COLLECT { … }

Types and values lists the literal forms of each type, and functions lists every function.

Operator precedence

Operators bind in this order, tightest first. Operators on one row have the same precedence and group from left to right, except the comparison row, which chains.

LevelOperatorsGroupingExampleResult
1.key, [index], [from..to]Postfix[1, 2, 3][1] * 24
2Unary -, unary +Prefix-2 ^ 24.0
3^Left to right2 ^ 3 ^ 264.0
4*, /, %Left to right2 * 3 % 42
5+, -, ||Left to right10 - 4 - 33
6IN, STARTS WITH, ENDS WITH, CONTAINS, IS [NOT] NULL, IS [NOT] :: <type>, IS [NOT] NORMALIZEDLeft to right1 + 2 IN [3]true
7=, <>, <, >, <=, >=, =~Chained: a < b < c is a < b AND b < c1 < 2 < 3true
8NOTPrefixNOT true = falsetrue
9ANDLeft to righttrue OR false AND falsetrue
10XORLeft to righttrue XOR true AND falsetrue
11ORLeft to rightfalse AND false OR truetrue

Parentheses override the table. Two rows surprise readers who come from other languages: unary minus binds tighter than ^, so -x ^ 2 is (-x) ^ 2, and a comparison chains, so 1 < 2 = true is 1 < 2 AND 2 = true, which is false.

Cypher
WITH 2 AS x
RETURN -x ^ 2 AS neg_first, -(x ^ 2) AS pow_first, 2 ^ 3 ^ 2 AS left_assoc,
       1 = 1 IN [true] AS in_binds_tighter, 1 < 2 = true AS chained,
       (1 < 2) = true AS grouped, true XOR true AND false AS xor_and
Recorded result
neg_firstpow_firstleft_associn_binds_tighterchainedgroupedxor_and
4.0-4.064.0falsefalsetruetrue

1 row

Arithmetic

OperatorOperandsResultEdge cases
+, -, *Two integersINTEGEROverflow fails with type error: integer out of range
+, -, *A float and a numberFLOATIEEE 754 64-bit arithmetic
/Two integersINTEGER, truncated toward zero: -7 / 2 is -31 / 0 fails with type error: / by zero
/A float and a numberFLOAT1 / 0.0 is Infinity
%Two integersINTEGER; the sign follows the dividend: -7 % 3 is -11 % 0 fails with type error: % by zero
%A float and a numberFLOAT: 7.5 % 2 is 1.5—
^Two numbersAlways FLOAT: 2 ^ 3 is 8.02 ^ -1 is 0.5
-One numberThe negation—
+, -Temporal values and durationsSee temporal arithmetic—
Cypher
RETURN 7 / 2 AS int_div, -7 / 2 AS truncates, -7 % 3 AS remainder,
       7.0 / 2 AS float_div, 2 ^ 3 AS power, 0.1 + 0.2 AS ieee
Recorded result
int_divtruncatesremainderfloat_divpowerieee
3-3-13.58.00.30000000000000004

1 row

Cypher
RETURN 1 / 0 AS boom
Expected error
error: type error: / by zero

Comparison and equality

OperatorMeaningRules
=EqualAn integer equals a float of the same value (1 = 1.0 is true). Values of different types are not equal ('1' = 1 is false). Lists are equal element by element, maps key by key. NaN = NaN is false
<>Not equalThe negation of =, with the same null rule
<, >, <=, >=OrderNumbers by value, strings by code point ('B' < 'a' is true), booleans with false < true, lists element by element ([1, 2] < [1, 2, 0] is true), temporal values of the same type by instant. Values that have no order between them give null: 1 < 'a', a DATE against a ZONED DATETIME, two points
=~Regular expression matchThe whole string must match: 'Ada' =~ 'A' is false. (?i) at the start ignores case

Any comparison with a null operand gives null, and so does an equality between two lists or maps that are equal except where one holds null ([1, null] = [1, null] is null). IS NULL and IS NOT NULL are the tests that never give null.

Cypher
RETURN 1 = 1.0 AS int_float, '1' = 1 AS cross_type, 1 < 'a' AS unordered,
       'B' < 'a' AS code_point, [1, 2] < [1, 2, 0] AS lists,
       NaN = NaN AS nan, [1, null] = [1, null] AS null_inside, 'Ada' =~ '(?i)ada' AS regex
Recorded result
int_floatcross_typeunorderedcode_pointlistsnannull_insideregex
truefalsenulltruetruefalsenulltrue

1 row

Null and three-valued logic

null stands for a missing or unknown value. An operator or function that gets null returns null unless its row says otherwise; AND, OR and XOR follow three-valued logic:

aba AND ba OR ba XOR bNOT a
truenullnulltruenullfalse
falsenullfalsenullnulltrue
nullnullnullnullnullnull
ExpressionResultRule
null = nullnullEquality with null is unknown
x IS NULLtrue or falseThe test for a missing value
1 + nullnullArithmetic propagates null
2 IN [1, null]nullNot found, but the null element might have matched
1 IN [1, null]trueFound before the null matters
null IN [1]nullMembership of an unknown value
n.missingnullA property that is not set reads as null
[1, 2][5]nullAn index past the end
coalesce(null, 1)1The first argument that is not null

A WHERE keeps a row only when its predicate is true; false and null both drop it. A property set to null is removed, so keys(n) does not list it.

Cypher
RETURN null = null AS eq, null IS NULL AS is_null, true AND null AS and_null,
       false AND null AS false_and, true OR null AS or_null,
       2 IN [1, null] AS maybe, 1 IN [1, null] AS found, coalesce(null, 1) AS first
Recorded result
eqis_nulland_nullfalse_andor_nullmaybefoundfirst
nulltruenullfalsetruenulltrue1

1 row

String operators

OperatorResultNotes
a + bConcatenationA number on either side is converted: 'a' + 1 is 'a1'
a || bConcatenationBoth sides must be strings; otherwise type error: InvalidArgumentType: || requires two strings or two lists
a STARTS WITH bBOOLEANCase-sensitive
a ENDS WITH bBOOLEANCase-sensitive
a CONTAINS bBOOLEANCase-sensitive
a =~ <regex>BOOLEANThe whole string must match; a comparison operator, so it chains
a IS [NOT] [NFC | NFD | NFKC | NFKD] NORMALIZEDBOOLEANUnicode normalization test; the form defaults to NFC
s'… {<expression>} …'Interpolated string\{ and \} are literal braces; an embedded null makes the whole string null
Cypher
RETURN 'rel' + 'ate' AS plus, 'rel' || 'ate' AS concat, 'a' + 1 AS mixed,
       'relate' STARTS WITH 'rel' AS starts, 'relate' CONTAINS 'lat' AS contains,
       'abc' IS NFC NORMALIZED AS normalized, s'{1 + 1} items' AS interpolated
Recorded result
plusconcatmixedstartscontainsnormalizedinterpolated
"relate""relate""a1"truetruetrue"2 items"

1 row

List operators

OperatorResultNotes
a + bConcatenationA non-list on the right is appended: [1] + 2 is [1, 2]
a || bConcatenationBoth sides must be lists
x IN listBOOLEANElement equality, with the null rule of the null table; a list can be an element: [1] IN [[1]] is true
list[i]The element at iZero-based; a negative index counts from the end ([1, 2, 3][-1] is 3); past the end is null. A float index fails with InvalidArgumentType: list index must be an integer
list[from..to]A sublistfrom is included and to is not; either bound may be left out or negative; bounds outside the list are clamped

A subscript on a string fails with type error: InvalidArgumentType: subscript requires a list or map; substring() and left() take characters from a string.

Cypher
RETURN [1, 2] + [3] AS plus, [1] + 2 AS append, [1, 2, 3][0] AS first,
       [1, 2, 3][-1] AS last, [1, 2, 3, 4][1..3] AS slice, [1, 2, 3][5] AS past_end,
       [1] IN [[1]] AS nested
Recorded result
plusappendfirstlastslicepast_endnested
[1, 2, 3][1, 2]13[2, 3]nulltrue

1 row

Map and property access

FormResultNotes
m.key, n.keyThe value under keynull when the key is absent
m['key'], n[$key], n[k]The value under a computed keyA dynamic key on a node or relationship never uses an index; on an indexed label EXPLAIN reports notification 03N95 (notifications)
a + b on two mapsA merged mapA key in b replaces the same key in a: {a: 1} + {a: 2, b: 3} is {a: 2, b: 3}
{i IN list | <key>: <value>}A map comprehensionOne entry per element; a key that is not a string fails with type error: map comprehension key expression must be a STRING

CASE

FormSyntaxResult
SimpleCASE <expr> WHEN <value> THEN <result> … [ELSE <default>] ENDThe first THEN whose value equals <expr>
Simple, several valuesCASE <expr> WHEN <v1>, <v2> THEN <result> … ENDThe first THEN with any matching value
Simple, comparisonCASE <expr> WHEN > <value> THEN <result> … ENDThe first THEN whose comparison holds
GenericCASE WHEN <predicate> THEN <result> … [ELSE <default>] ENDThe first THEN whose predicate is true

Without ELSE, a CASE that matches nothing gives null.

Cypher
RETURN CASE 2 WHEN 1 THEN 'one' WHEN 2 THEN 'two' ELSE 'many' END AS simple,
       CASE 2 WHEN 1, 2 THEN 'small' ELSE 'big' END AS several,
       CASE 5 WHEN > 3 THEN 'above three' ELSE 'three or less' END AS comparison,
       CASE WHEN 1 > 2 THEN 'never' END AS no_else
Recorded result
simpleseveralcomparisonno_else
"two""small""above three"null

1 row

List and pattern comprehensions

A list comprehension builds a list from another list; a pattern comprehension builds one from the matches of a pattern, once per row.

FormResult
[x IN list WHERE <predicate>]The elements for which the predicate is true
[x IN list | <expression>]The expression for every element
[x IN list WHERE <predicate> | <expression>]Both
[<pattern> WHERE <predicate> | <expression>]The expression for every match of the pattern, which usually starts from a variable of the current row

The pattern cells on this page run on the shared example graph:

Cypher
CREATE (ada:Person {name: 'Ada', role: 'engineer'}),
       (grace:Person {name: 'Grace', role: 'engineer'}),
       (noor:Person {name: 'Noor', role: 'maintainer'}),
       (relate:Project {name: 'relate', language: 'Rust'}),
       (tck:Project {name: 'opencypher-tck', language: 'Gherkin'}),
       (ada)-[:WORKS_ON {since: 2024}]->(relate),
       (grace)-[:WORKS_ON {since: 2023}]->(relate),
       (grace)-[:WORKS_ON {since: 2022}]->(tck),
       (noor)-[:MAINTAINS]->(relate),
       (ada)-[:KNOWS]->(grace)
Recorded result
(no rows) · nodes created: 5, relationships created: 5, properties set: 13, labels added: 5
Cypher
MATCH (p:Person {name: 'Grace'})
RETURN [x IN range(1, 10) WHERE x % 2 = 0 | x * x] AS even_squares,
       [(p)-[w:WORKS_ON]->(proj) WHERE w.since >= 2023 | proj.name] AS recent_projects
Recorded result
even_squaresrecent_projects
[4, 16, 36, 64, 100]["relate"]

1 row

Map projections

A map projection builds a map from a node, a relationship, or a map variable.

ItemAdds
.keyThe property key, or null when it is not set
.*Every property
key: <expression>A computed entry, which may hold a pattern comprehension
varThe value of the variable var, under its own name
Cypher
MATCH (p:Person)
RETURN p {.name, .role, projects: [(p)-[:WORKS_ON]->(proj) | proj.name]} AS person
ORDER BY person.name
Recorded result
person
{name: "Ada", projects: ["relate"], role: "engineer"}
{name: "Grace", projects: ["opencypher-tck", "relate"], role: "engineer"}
{name: "Noor", projects: [], role: "maintainer"}

3 rows

reduce and allReduce

FormResult
reduce(acc = <initial>, x IN list | <expression>)Evaluates the expression for each element in order, with acc holding the previous result; returns the last
allReduce(acc = <initial>, x IN list | <expression>, <predicate>)true when the predicate holds for the accumulator after every step; stops at the first step where it fails
Cypher
RETURN reduce(total = 0, x IN [1, 2, 3, 4] | total + x) AS total,
       allReduce(s = 0, x IN [1, 2, 3] | s + x, s < 5) AS stays_under_five
Recorded result
totalstays_under_five
10false

1 row

List predicates

Predicatetrue whenOn an empty list
all(x IN list WHERE p)p is true for every elementtrue
any(x IN list WHERE p)p is true for at least one elementfalse
none(x IN list WHERE p)p is true for no elementtrue
single(x IN list WHERE p)p is true for exactly one elementfalse

When no element decides the answer and p gives null for some element, the predicate gives null: any(x IN [null] WHERE x > 1) is null.

Cypher
RETURN all(x IN [1, 2] WHERE x > 0) AS all_positive, any(x IN [1, 2] WHERE x > 1) AS any_big,
       none(x IN [1, 2] WHERE x > 5) AS none_huge, single(x IN [1, 2] WHERE x > 1) AS one_big,
       all(x IN [] WHERE false) AS empty_all, any(x IN [null] WHERE x > 1) AS unknown
Recorded result
all_positiveany_bignone_hugeone_bigempty_allunknown
truetruetruetruetruenull

1 row

Type predicates

<expression> IS :: <type> tests a value's type; IS NOT :: negates it. IS TYPED <type> and :: <type> are the same test. The type names are the ones valueType() returns (types and values).

FormRule
x IS :: INTEGERtrue for an integer, and for null: every type includes null unless it says NOT NULL
x IS :: INTEGER NOT NULLfalse for null
x IS :: INTEGER | STRINGtrue for either type
x IS :: LIST<INTEGER>true for a list whose elements are all integers
x IS :: ANYtrue for every value
valueType(x)The type name as a string, with its nullability: valueType(1) is 'INTEGER NOT NULL'
Cypher
RETURN 5 IS :: INTEGER AS int, null IS :: INTEGER AS null_is_int,
       null IS :: INTEGER NOT NULL AS not_null, 1 IS :: INTEGER | STRING AS union_type,
       [1] IS :: LIST<INTEGER> AS list_type, valueType([1, 'two']) AS mixed
Recorded result
intnull_is_intnot_nullunion_typelist_typemixed
truetruefalsetruetrue"LIST<STRING NOT NULL | INTEGER NOT NULL> NOT NULL"

1 row

Subquery expressions

FormResult
EXISTS { <pattern or statement> }true when the subquery returns at least one row
COUNT { <pattern or statement> }The number of rows
COLLECT { <statement> }A list of the single column the statement returns

Variables of the outer row are visible inside. Composing clauses covers CALL subqueries, which return more than one column.

Cypher
MATCH (p:Person {name: 'Grace'})
RETURN COUNT { (p)-[:WORKS_ON]->() } AS projects,
       EXISTS { (p)<-[:KNOWS]-() } AS known,
       COLLECT { MATCH (p)-[:WORKS_ON]->(proj) RETURN proj.name ORDER BY proj.name } AS names
Recorded result
projectsknownnames
2true["opencypher-tck", "relate"]

1 row

See also

  • Types and values: every value type, its literal form, and how it serializes.
  • Functions: every built-in function, by category.
  • Patterns: node, relationship, and path patterns, label expressions, and quantifiers.
  • Use parameters: passing values into a statement with $name.
  • Differences from Neo4j: the forms an agent trained on Neo4j Cypher may reach for.