## 2.7. Operators

### 2.7.1. Operators at a glance

 Aggregation operators `DISTINCT` Property operators `.` for static property access, `[]` for dynamic property access, `=` for replacing all properties, `+=` for mutating specific properties Mathematical operators `+`, `-`, `*`, `/`, `%`, `^` Comparison operators `=`, `<>`, `<`, `>`, `<=`, `>=`, `IS NULL`, `IS NOT NULL` String-specific comparison operators `STARTS WITH`, `ENDS WITH`, `CONTAINS` Boolean operators `AND`, `OR`, `XOR`, `NOT` String operators `+` for concatenation, `=~` for regex matching Temporal operators `+` and `-` for operations between durations and temporal instants/durations, `*` and `/` for operations between durations and numbers Map operators `.` for static value access by key, `[]` for dynamic value access by key List operators `+` for concatenation, `IN` to check existence of an element in a list, `[]` for accessing element(s) dynamically

### 2.7.2. Aggregation operators

The aggregation operators comprise:

• remove duplicates values: `DISTINCT`

#### 2.7.2.1. Using the `DISTINCT` operator

Retrieve the unique eye colors from `Person` nodes.

Query.

``````CREATE (a:Person { name: 'Anne', eyeColor: 'blue' }),(b:Person { name: 'Bill', eyeColor: 'brown' }),(c:Person { name: 'Carol', eyeColor: 'blue' })
WITH [a, b, c] AS ps
UNWIND ps AS p
RETURN DISTINCT p.eyeColor``````

Even though both 'Anne' and 'Carol' have blue eyes, 'blue' is only returned once.

Table 2.5. Result
p.eyeColor

2 rows Nodes created: 3 Properties set: 6 Labels added: 3

`"blue"`

`"brown"`

Try this query live.  none CREATE (a:Person {name: 'Anne', eyeColor: 'blue'}), (b:Person {name: 'Bill', eyeColor: 'brown'}), (c:Person {name: 'Carol', eyeColor: 'blue'}) WITH [a, b, c] AS ps UNWIND ps AS p RETURN DISTINCT p.eyeColor

`DISTINCT` is commonly used in conjunction with aggregating functions.

### 2.7.3. Property operators

The property operators pertain to a node or a relationship, and comprise:

• statically access the property of a node or relationship using the dot operator: `.`
• dynamically access the property of a node or relationship using the subscript operator: `[]`
• property replacement `=` for replacing all properties of a node or relationship
• property mutation operator `+=` for setting specific properties of a node or relationship

#### 2.7.3.1. Statically accessing a property of a node or relationship using the `.` operator

Query.

``````CREATE (a:Person { name: 'Jane', livesIn: 'London' }),(b:Person { name: 'Tom', livesIn: 'Copenhagen' })
WITH a, b
MATCH (p:Person)
RETURN p.name``````

Table 2.6. Result
p.name

2 rows Nodes created: 2 Properties set: 4 Labels added: 2

`"Jane"`

`"Tom"`

Try this query live.  none CREATE (a:Person {name: 'Jane', livesIn: 'London'}), (b:Person {name: 'Tom', livesIn: 'Copenhagen'}) WITH a, b MATCH (p:Person) RETURN p.name

#### 2.7.3.2. Filtering on a dynamically-computed property key using the `[]` operator

Query.

``````CREATE (a:Restaurant { name: 'Hungry Jo', rating_hygiene: 10, rating_food: 7 }),(b:Restaurant { name: 'Buttercup Tea Rooms', rating_hygiene: 5, rating_food: 6 }),(c1:Category { name: 'hygiene' }),(c2:Category { name: 'food' })
WITH a, b, c1, c2
MATCH (restaurant:Restaurant),(category:Category)
WHERE restaurant["rating_" + category.name]> 6
RETURN DISTINCT restaurant.name``````

Table 2.7. Result
restaurant.name

1 row Nodes created: 4 Properties set: 8 Labels added: 4

`"Hungry Jo"`

Try this query live.  none CREATE (a:Restaurant {name: 'Hungry Jo', rating_hygiene: 10, rating_food: 7}), (b:Restaurant {name: 'Buttercup Tea Rooms', rating_hygiene: 5, rating_food: 6}), (c1:Category {name: 'hygiene'}), (c2:Category {name: 'food'}) WITH a, b, c1, c2 MATCH (restaurant:Restaurant), (category:Category) WHERE restaurant["rating_" + category.name] > 6 RETURN DISTINCT restaurant.name

See Section 3.7.2, “Basic usage” for more details on dynamic property access.

 The behavior of the `[]` operator with respect to `null` is detailed here.

#### 2.7.3.3. Replacing all properties of a node or relationship using the `=` operator

Query.

``````CREATE (a:Person { name: 'Jane', age: 20 })
WITH a
MATCH (p:Person { name: 'Jane' })
SET p = { name: 'Ellen', livesIn: 'London' }
RETURN p.name, p.age, p.livesIn``````

All the existing properties on the node are replaced by those provided in the map; i.e. the `name` property is updated from `Jane` to `Ellen`, the `age` property is deleted, and the `livesIn` property is added.

Table 2.8. Result
p.name p.age p.livesIn

1 row Nodes created: 1 Properties set: 5 Labels added: 1

`"Ellen"`

`<null>`

`"London"`

Try this query live.  none CREATE (a:Person {name: 'Jane', age: 20}) WITH a MATCH (p:Person {name: 'Jane'}) SET p = {name: 'Ellen', livesIn: 'London'} RETURN p.name, p.age, p.livesIn

See Section 3.13.6, “Replace all properties using a map and `=` for more details on using the property replacement operator `=`.

#### 2.7.3.4. Mutating specific properties of a node or relationship using the `+=` operator

Query.

``````CREATE (a:Person { name: 'Jane', age: 20 })
WITH a
MATCH (p:Person { name: 'Jane' })
SET p += { name: 'Ellen', livesIn: 'London' }
RETURN p.name, p.age, p.livesIn``````

The properties on the node are updated as follows by those provided in the map: the `name` property is updated from `Jane` to `Ellen`, the `age` property is left untouched, and the `livesIn` property is added.

Table 2.9. Result
p.name p.age p.livesIn

1 row Nodes created: 1 Properties set: 4 Labels added: 1

`"Ellen"`

`20`

`"London"`

Try this query live.  none CREATE (a:Person {name: 'Jane', age: 20}) WITH a MATCH (p:Person {name: 'Jane'}) SET p += {name: 'Ellen', livesIn: 'London'} RETURN p.name, p.age, p.livesIn

See Section 3.13.8, “Mutate specific properties using a map and `+=` for more details on using the property mutation operator `+=`.

### 2.7.4. Mathematical operators

The mathematical operators comprise:

• addition: `+`
• subtraction or unary minus: `-`
• multiplication: `*`
• division: `/`
• modulo division: `%`
• exponentiation: `^`

#### 2.7.4.1. Using the exponentiation operator `^`

Query.

``````WITH 2 AS number, 3 AS exponent
RETURN number ^ exponent AS result``````

Table 2.10. Result
result

1 row

`8.0`

Try this query live.  none WITH 2 AS number, 3 AS exponent RETURN number ^ exponent AS result

#### 2.7.4.2. Using the unary minus operator `-`

Query.

``````WITH -3 AS a, 4 AS b
RETURN b - a AS result``````

Table 2.11. Result
result

1 row

`7`

Try this query live.  none WITH -3 AS a, 4 AS b RETURN b - a AS result

### 2.7.5. Comparison operators

The comparison operators comprise:

• equality: `=`
• inequality: `<>`
• less than: `<`
• greater than: `>`
• less than or equal to: `<=`
• greater than or equal to: `>=`
• `IS NULL`
• `IS NOT NULL`

#### 2.7.5.1. String-specific comparison operators comprise:

• `STARTS WITH`: perform case-sensitive prefix searching on strings
• `ENDS WITH`: perform case-sensitive suffix searching on strings
• `CONTAINS`: perform case-sensitive inclusion searching in strings

#### 2.7.5.2. Comparing two numbers

Query.

``````WITH 4 AS one, 3 AS two
RETURN one > two AS result``````

Table 2.12. Result
result

1 row

`true`

Try this query live.  none WITH 4 AS one, 3 AS two RETURN one > two AS result

See Section 2.7.11, “Equality and comparison of values” for more details on the behavior of comparison operators, and Section 3.7.8, “Using ranges” for more examples showing how these may be used.

#### 2.7.5.3. Using `STARTS WITH` to filter names

Query.

``````WITH ['John', 'Mark', 'Jonathan', 'Bill'] AS somenames
UNWIND somenames AS names
WITH names AS candidate
WHERE candidate STARTS WITH 'Jo'
RETURN candidate``````

Table 2.13. Result
candidate

2 rows

`"John"`

`"Jonathan"`

Try this query live.  none WITH ['John', 'Mark', 'Jonathan', 'Bill'] AS somenames UNWIND somenames AS names WITH names AS candidate WHERE candidate STARTS WITH 'Jo' RETURN candidate

Section 3.7.3, “String matching” contains more information regarding the string-specific comparison operators as well as additional examples illustrating the usage thereof.

### 2.7.6. Boolean operators

The boolean operators — also known as logical operators — comprise:

• conjunction: `AND`
• disjunction: `OR`,
• exclusive disjunction: `XOR`
• negation: `NOT`

Here is the truth table for `AND`, `OR`, `XOR` and `NOT`.

a b a `AND` b a `OR` b a `XOR` b `NOT` a

`false`

`false`

`false`

`false`

`false`

`true`

`false`

`null`

`false`

`null`

`null`

`true`

`false`

`true`

`false`

`true`

`true`

`true`

`true`

`false`

`false`

`true`

`true`

`false`

`true`

`null`

`null`

`true`

`null`

`false`

`true`

`true`

`true`

`true`

`false`

`false`

`null`

`false`

`false`

`null`

`null`

`null`

`null`

`null`

`null`

`null`

`null`

`null`

`null`

`true`

`null`

`true`

`null`

`null`

#### 2.7.6.1. Using boolean operators to filter numbers

Query.

``````WITH [2, 4, 7, 9, 12] AS numberlist
UNWIND numberlist AS number
WITH number
WHERE number = 4 OR (number > 6 AND number < 10)
RETURN number``````

Table 2.14. Result
number

3 rows

`4`

`7`

`9`

Try this query live.  none WITH [2, 4, 7, 9, 12] AS numberlist UNWIND numberlist AS number WITH number WHERE number = 4 OR (number > 6 AND number < 10) RETURN number

### 2.7.7. String operators

The string operators comprise:

• concatenating strings: `+`
• matching a regular expression: `=~`

#### 2.7.7.1. Using a regular expression with `=~` to filter words

Query.

``````WITH ['mouse', 'chair', 'door', 'house'] AS wordlist
UNWIND wordlist AS word
WITH word
WHERE word =~ '.*ous.*'
RETURN word``````

Table 2.15. Result
word

2 rows

`"mouse"`

`"house"`

Try this query live.  none WITH ['mouse', 'chair', 'door', 'house'] AS wordlist UNWIND wordlist AS word WITH word WHERE word =~ '.*ous.*' RETURN word

Further information and examples regarding the use of regular expressions in filtering can be found in Section 3.7.4, “Regular expressions”. In addition, refer to Section 2.7.5.1, “String-specific comparison operators comprise:” for details on string-specific comparison operators.

### 2.7.8. Temporal operators

Temporal operators comprise:

• adding a Duration to either a temporal instant or another Duration: `+`
• subtracting a Duration from either a temporal instant or another Duration: `-`
• multiplying a Duration with a number: `*`
• dividing a Duration by a number: `/`

The following table shows — for each combination of operation and operand type — the type of the value returned from the application of each temporal operator:

Operator Left-hand operand Right-hand operand Type of result

`+`

Temporal instant

Duration

The type of the temporal instant

`+`

Duration

Temporal instant

The type of the temporal instant

`-`

Temporal instant

Duration

The type of the temporal instant

`+`

Duration

Duration

Duration

`-`

Duration

Duration

Duration

`*`

Duration

Number

Duration

`*`

Number

Duration

Duration

`/`

Duration

Number

Duration

#### 2.7.8.1. Adding and subtracting a Duration to or from a temporal instant

Query.

``````WITH localdatetime({ year:1984, month:10, day:11, hour:12, minute:31, second:14 }) AS aDateTime, duration({ years: 12, nanoseconds: 2 }) AS aDuration

Table 2.16. Result

1 row

`1996-10-11T12:31:14.000000002`

`1972-10-11T12:31:13.999999998`

Components of a Duration that do not apply to the temporal instant are ignored. For example, when adding a Duration to a Date, the hours, minutes, seconds and nanoseconds of the Duration are ignored (Time behaves in an analogous manner):

Query.

``````WITH date({ year:1984, month:10, day:11 }) AS aDate, duration({ years: 12, nanoseconds: 2 }) AS aDuration

Table 2.17. Result

1 row

`1996-10-11`

`1972-10-11`

Adding two durations to a temporal instant is not an associative operation. This is because non-existing dates are truncated to the nearest existing date:

Query.

``RETURN (date("2011-01-31")+ duration("P1M"))+ duration("P12M") AS date1, date("2011-01-31")+(duration("P1M")+ duration("P12M")) AS date2``

Table 2.18. Result
date1 date2

1 row

`2012-02-28`

`2012-02-29`

Try this query live.  none RETURN (date("2011-01-31") + duration("P1M")) + duration("P12M") AS date1, date("2011-01-31") + (duration("P1M") + duration("P12M")) AS date2

#### 2.7.8.2. Adding and subtracting a Duration to or from another Duration

Query.

``````WITH duration({ years: 12, months: 5, days: 14, hours: 16, minutes: 12, seconds: 70, nanoseconds: 1 }) AS duration1, duration({ months:1, days: -14, hours: 16, minutes: -12, seconds: 70 }) AS duration2
RETURN duration1, duration2, duration1 + duration2, duration1 - duration2``````

Table 2.19. Result
duration1 duration2 duration1 + duration2 duration1 - duration2

1 row

`P12Y5M14DT16H13M10.000000001S`

`P1M-14DT15H49M10S`

`P12Y6MT32H2M20.000000001S`

`P12Y4M28DT24M0.000000001S`

Try this query live.  none WITH duration({years: 12, months: 5, days: 14, hours: 16, minutes: 12, seconds: 70, nanoseconds: 1}) as duration1, duration({months:1, days: -14, hours: 16, minutes: -12, seconds: 70}) AS duration2 RETURN duration1, duration2, duration1 + duration2, duration1 - duration2

#### 2.7.8.3. Multiplying and dividing a Duration with or by a number

These operations are interpreted simply as component-wise operations with overflow to smaller units based on an average length of units in the case of division (and multiplication with fractions).

Query.

``````WITH duration({ days: 14, minutes: 12, seconds: 70, nanoseconds: 1 }) AS aDuration

Table 2.20. Result

1 row

`P14DT13M10.000000001S`

`P28DT26M20.000000002S`

`P4DT16H4M23.333333333S`

Try this query live.  none WITH duration({days: 14, minutes: 12, seconds: 70, nanoseconds: 1}) AS aDuration RETURN aDuration, aDuration * 2, aDuration / 3

### 2.7.9. Map operators

The map operators comprise:

• statically access the value of a map by key using the dot operator: `.`
• dynamically access the value of a map by key using the subscript operator: `[]`
 The behavior of the `[]` operator with respect to `null` is detailed in Section 2.14.4, “The `[]` operator and `null`”.

#### 2.7.9.1. Statically accessing the value of a nested map by key using the `.` operator

Query.

``````WITH { person: { name: 'Anne', age: 25 }} AS p
RETURN p.person.name``````

Table 2.21. Result
p.person.name

1 row

`"Anne"`

Try this query live.  none WITH {person: {name: 'Anne', age: 25}} AS p RETURN p.person.name

#### 2.7.9.2. Dynamically accessing the value of a map by key using the `[]` operator and a parameter

A parameter may be used to specify the key of the value to access:

Parameters.

``````{
"myKey" : "name"
}``````

Query.

``````WITH { name: 'Anne', age: 25 } AS a
RETURN a[\$myKey] AS result``````

Table 2.22. Result
result

1 row

`"Anne"`

Try this query live.  none WITH {name: 'Anne', age: 25} AS a RETURN a[\$myKey] AS result

More details on maps can be found in Section 2.12, “Maps”.

### 2.7.10. List operators

The list operators comprise:

• concatenating lists `l1` and `l2`: `[l1] + [l2]`
• checking if an element `e` exists in a list `l`: `e IN [l]`
• dynamically accessing an element(s) in a list using the subscript operator: `[]`
 The behavior of the `IN` and `[]` operators with respect to `null` is detailed here.

#### 2.7.10.1. Concatenating two lists using `+`

Query.

``RETURN [1,2,3,4,5]+[6,7] AS myList``

Table 2.23. Result
myList

1 row

`[1,2,3,4,5,6,7]`

Try this query live.  none RETURN [1,2,3,4,5] + [6,7] AS myList

#### 2.7.10.2. Using `IN` to check if a number is in a list

Query.

``````WITH [2, 3, 4, 5] AS numberlist
UNWIND numberlist AS number
WITH number
WHERE number IN [2, 3, 8]
RETURN number``````

Table 2.24. Result
number

2 rows

`2`

`3`

Try this query live.  none WITH [2, 3, 4, 5] AS numberlist UNWIND numberlist AS number WITH number WHERE number IN [2, 3, 8] RETURN number

#### 2.7.10.3. Using `IN` for more complex list membership operations

The general rule is that the `IN` operator will evaluate to `true` if the list given as the right-hand operand contains an element which has the same type and contents (or value) as the left-hand operand. Lists are only comparable to other lists, and elements of a list `l` are compared pairwise in ascending order from the first element in `l` to the last element in `l`.

The following query checks whether or not the list `[2, 1]` is an element of the list `[1, [2, 1], 3]`:

Query.

``RETURN [2, 1] IN [1,[2, 1], 3] AS inList``

The query evaluates to `true` as the right-hand list contains, as an element, the list `[1, 2]` which is of the same type (a list) and contains the same contents (the numbers `2` and `1` in the given order) as the left-hand operand. If the left-hand operator had been `[1, 2]` instead of `[2, 1]`, the query would have returned `false`.

Table 2.25. Result
inList

1 row

`true`

Try this query live.  none RETURN [2, 1] IN [1, [2, 1], 3] AS inList

At first glance, the contents of the left-hand operand and the right-hand operand appear to be the same in the following query:

Query.

``RETURN [1, 2] IN [1, 2] AS inList``

However, `IN` evaluates to `false` as the right-hand operand does not contain an element that is of the same type — i.e. a list — as the left-hand-operand.

Table 2.26. Result
inList

1 row

`false`

Try this query live.  none RETURN [1, 2] IN [1, 2] AS inList

The following query can be used to ascertain whether or not a list `llhs` — obtained from, say, the labels() function — contains at least one element that is also present in another list `lrhs`:

``````MATCH (n)
WHERE size([l IN labels(n) WHERE l IN ['Person', 'Employee'] | 1]) > 0
RETURN count(n)``````

As long as `labels(n)` returns either `Person` or `Employee` (or both), the query will return a value greater than zero.

#### 2.7.10.4. Accessing elements in a list using the `[]` operator

Query.

``````WITH ['Anne', 'John', 'Bill', 'Diane', 'Eve'] AS names
RETURN names[1..3] AS result``````

The square brackets will extract the elements from the start index `1`, and up to (but excluding) the end index `3`.

Table 2.27. Result
result

1 row

`["John","Bill"]`

Try this query live.  none WITH ['Anne', 'John', 'Bill', 'Diane', 'Eve'] AS names RETURN names[1..3] AS result

#### 2.7.10.5. Dynamically accessing an element in a list using the `[]` operator and a parameter

A parameter may be used to specify the index of the element to access:

Parameters.

``````{
"myIndex" : 1
}``````

Query.

``````WITH ['Anne', 'John', 'Bill', 'Diane', 'Eve'] AS names
RETURN names[\$myIndex] AS result``````

Table 2.28. Result
result

1 row

`"John"`

Try this query live.  none WITH ['Anne', 'John', 'Bill', 'Diane', 'Eve'] AS names RETURN names[\$myIndex] AS result

#### 2.7.10.6. Using `IN` with `[]` on a nested list

`IN` can be used in conjunction with `[]` to test whether an element exists in a nested list:

Parameters.

``````{
"myIndex" : 1
}``````

Query.

``````WITH [[1, 2, 3]] AS l
RETURN 3 IN l[0] AS result``````

Table 2.29. Result
result

1 row

`true`

Try this query live.  none WITH [[1, 2, 3]] AS l RETURN 3 IN l[0] AS result

More details on lists can be found in Section 2.11.1, “Lists in general”.

### 2.7.11. Equality and comparison of values

#### 2.7.11.1. Equality

Cypher supports comparing values (see Section 2.1, “Values and types”) by equality using the `=` and `<>` operators.

Values of the same type are only equal if they are the same identical value (e.g. `3 = 3` and `"x" <> "xy"`).

Maps are only equal if they map exactly the same keys to equal values and lists are only equal if they contain the same sequence of equal values (e.g. `[3, 4] = [1+2, 8/2]`).

Values of different types are considered as equal according to the following rules:

• Paths are treated as lists of alternating nodes and relationships and are equal to all lists that contain that very same sequence of nodes and relationships.
• Testing any value against `null` with both the `=` and the `<>` operators always is `null`. This includes `null = null` and `null <> null`. The only way to reliably test if a value `v` is `null` is by using the special `v IS NULL`, or `v IS NOT NULL` equality operators.

All other combinations of types of values cannot be compared with each other. Especially, nodes, relationships, and literal maps are incomparable with each other.

It is an error to compare values that cannot be compared.

### 2.7.12. Ordering and comparison of values

The comparison operators `<=`, `<` (for ascending) and `>=`, `>` (for descending) are used to compare values for ordering. The following points give some details on how the comparison is performed.

• Numerical values are compared for ordering using numerical order (e.g. `3 < 4` is true).
• The special value `java.lang.Double.NaN` is regarded as being larger than all other numbers.
• String values are compared for ordering using lexicographic order (e.g. `"x" < "xy"`).
• Boolean values are compared for ordering such that `false < true`.
• Comparison of spatial values:

• Point values can only be compared within the same Coordinate Reference System (CRS) — otherwise, the result will be `null`.
• For two points `a` and `b` within the same CRS, `a` is considered to be greater than `b` if `a.x > b.x` and `a.y > b.y` (and `a.z > b.z` for 3D points).
• `a` is considered less than `b` if `a.x < b.x` and `a.y < b.y` (and `a.z < b.z` for 3D points).
• If none if the above is true, the points are considered incomparable and any comparison operator between them will return `null`.
• Ordering of spatial values:

• `ORDER BY` requires all values to be orderable.
• Points are ordered after arrays and before temporal types.
• Points of different CRS are ordered by the CRS code (the value of SRID field). For the currently supported set of Coordinate Reference Systems this means the order: 4326, 4979, 7302, 9157
• Points of the same CRS are ordered by each coordinate value in turn, `x` first, then `y` and finally `z`.
• Note that this order is different to the order returned by the spatial index, which will be the order of the space filling curve.
• Comparison of temporal values:

• Temporal instant values are comparable within the same type. An instant is considered less than another instant if it occurs before that instant in time, and it is considered greater than if it occurs after.
• Instant values that occur at the same point in time — but that have a different time zone — are not considered equal, and must therefore be ordered in some predictable way. Cypher prescribes that, after the primary order of point in time, instant values be ordered by effective time zone offset, from west (negative offset from UTC) to east (positive offset from UTC). This has the effect that times that represent the same point in time will be ordered with the time with the earliest local time first. If two instant values represent the same point in time, and have the same time zone offset, but a different named time zone (this is possible for DateTime only, since Time only has an offset), these values are not considered equal, and ordered by the time zone identifier, alphabetically, as its third ordering component.
• Duration values cannot be compared, since the length of a day, month or year is not known without knowing which day, month or year it is. Since Duration values are not comparable, the result of applying a comparison operator between two Duration values is `null`. If the type, point in time, offset, and time zone name are all equal, then the values are equal, and any difference in order is impossible to observe.
• Ordering of temporal values:

• `ORDER BY` requires all values to be orderable.
• Temporal instances are ordered after spatial instances and before strings.
• Comparable values should be ordered in the same order as implied by their comparison order.
• Temporal instant values are first ordered by type, and then by comparison order within the type.
• Since no complete comparison order can be defined for Duration values, we define an order for `ORDER BY` specifically for Duration:

• Duration values are ordered by normalising all components as if all years were `365.2425` days long (`PT8765H49M12S`), all months were `30.436875` (`1/12` year) days long (`PT730H29M06S`), and all days were `24` hours long [1].
• Comparing for ordering when one argument is `null` (e.g. `null < 3` is `null`).

### 2.7.13. Chaining comparison operations

Comparisons can be chained arbitrarily, e.g., `x < y <= z` is equivalent to `x < y AND y <= z`.

Formally, if `a, b, c, ..., y, z` are expressions and `op1, op2, ..., opN` are comparison operators, then `a op1 b op2 c ... y opN z` is equivalent to `a op1 b and b op2 c and ... y opN z`.

Note that `a op1 b op2 c` does not imply any kind of comparison between `a` and `c`, so that, e.g., `x < y > z` is perfectly legal (although perhaps not elegant).

The example:

``MATCH (n) WHERE 21 < n.age <= 30 RETURN n``

is equivalent to

``MATCH (n) WHERE 21 < n.age AND n.age <= 30 RETURN n``

Thus it will match all nodes where the age is between 21 and 30.

This syntax extends to all equality and inequality comparisons, as well as extending to chains longer than three.

For example:

``a < b = c <= d <> e``

Is equivalent to:

``a < b AND b = c AND c <= d AND d <> e``

For other comparison operators, see Section 2.7.5, “Comparison operators”.

[1] The `365.2425` days per year comes from the frequency of leap years. A leap year occurs on a year with an ordinal number divisible by `4`, that is not divisible by `100`, unless it divisible by `400`. This means that over `400` years there are `((365 * 4 + 1) * 25 - 1) * 4 + 1 = 146097` days, which means an average of `365.2425` days per year.