diff --git a/modules/ROOT/content-nav.adoc b/modules/ROOT/content-nav.adoc
index d6ea0bd0d..375e299a3 100644
--- a/modules/ROOT/content-nav.adoc
+++ b/modules/ROOT/content-nav.adoc
@@ -6,8 +6,7 @@
* xref:queries/index.adoc[]
** xref:queries/concepts.adoc[]
** xref:queries/basic.adoc[]
-** xref:queries/expressions.adoc[]
-** xref:queries/case.adoc[]
+** xref:queries/combined-queries.adoc[]
* xref:clauses/index.adoc[]
** xref:clauses/clause-composition.adoc[]
@@ -31,7 +30,6 @@
** xref:clauses/transaction-clauses.adoc#query-listing-transactions[SHOW TRANSACTIONS]
** xref:clauses/skip.adoc[]
** xref:clauses/transaction-clauses.adoc#query-terminate-transactions[TERMINATE TRANSACTIONS]
-** xref:clauses/union.adoc[]
** xref:clauses/unwind.adoc[]
** xref:clauses/use.adoc[]
** xref:clauses/where.adoc[]
@@ -52,16 +50,32 @@
** xref:patterns/non-linear-patterns.adoc[]
** xref:patterns/reference.adoc[]
-
* xref:values-and-types/index.adoc[]
-** xref:values-and-types/property-structural-constructed.adoc[]
-** xref:values-and-types/temporal.adoc[]
-** xref:values-and-types/spatial.adoc[]
-** xref:values-and-types/working-with-null.adoc[]
-** xref:values-and-types/lists.adoc[]
-** xref:values-and-types/maps.adoc[]
-** xref:values-and-types/casting-data.adoc[]
-** xref:values-and-types/type-predicate.adoc[]
+** xref::values-and-types/property-structural-constructed.adoc[]
+** xref:values-and-types/boolean-numeric-string.adoc[]
+** xref::values-and-types/temporal.adoc[]
+** xref::values-and-types/spatial.adoc[]
+** xref::values-and-types/lists.adoc[]
+** xref::values-and-types/maps.adoc[]
+** xref::values-and-types/working-with-null.adoc[]
+** xref::values-and-types/casting-data.adoc[]
+** xref:values-and-types/ordering-equality-comparison.adoc[]
+
+* xref:expressions/index.adoc[]
+** xref:expressions/predicates/index.adoc[]
+*** xref:expressions/predicates/boolean-operators.adoc[]
+*** xref:expressions/predicates/comparison-operators.adoc[]
+*** xref:expressions/predicates/list-operators.adoc[]
+*** xref:expressions/predicates/string-operators.adoc[]
+*** xref:expressions/predicates/path-pattern-expressions.adoc[]
+*** xref:expressions/predicates/type-predicate-expressions.adoc[]
+** xref:expressions/node-relationship-operators.adoc[]
+** xref:expressions/mathematical-operators.adoc[]
+** xref:expressions/string-operators.adoc[]
+** xref:expressions/temporal-operators.adoc[]
+** xref:expressions/list-expressions.adoc[]
+** xref:expressions/map-expressions.adoc[]
+** xref:expressions/conditional-expressions.adoc[]
* xref:functions/index.adoc[]
** xref:functions/aggregating.adoc[]
@@ -81,7 +95,6 @@
** xref:functions/user-defined.adoc[]
** xref:functions/vector.adoc[]
-
* xref:genai-integrations.adoc[]
* xref:indexes/index.adoc[]
** xref:indexes/search-performance-indexes/overview.adoc[]
@@ -118,7 +131,6 @@
** xref:syntax/variables.adoc[]
** xref:syntax/keywords.adoc[]
** xref:syntax/parameters.adoc[]
-** xref:syntax/operators.adoc[]
** xref:syntax/comments.adoc[]
* xref:deprecations-additions-removals-compatibility.adoc[]
diff --git a/modules/ROOT/images/conditional_query_graph.svg b/modules/ROOT/images/conditional_query_graph.svg
new file mode 100644
index 000000000..4e3d7b1a0
--- /dev/null
+++ b/modules/ROOT/images/conditional_query_graph.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/modules/ROOT/images/graph_element_operators.svg b/modules/ROOT/images/graph_element_operators.svg
new file mode 100644
index 000000000..1617bf92f
--- /dev/null
+++ b/modules/ROOT/images/graph_element_operators.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/modules/ROOT/images/graph_where_clause.svg b/modules/ROOT/images/graph_where_clause.svg
index b307c8355..f15e25ef6 100644
--- a/modules/ROOT/images/graph_where_clause.svg
+++ b/modules/ROOT/images/graph_where_clause.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/modules/ROOT/images/list_expressions_graph.svg b/modules/ROOT/images/list_expressions_graph.svg
new file mode 100644
index 000000000..3fdbc2779
--- /dev/null
+++ b/modules/ROOT/images/list_expressions_graph.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/modules/ROOT/images/path_pattern_expressions.svg b/modules/ROOT/images/path_pattern_expressions.svg
new file mode 100644
index 000000000..e236e0637
--- /dev/null
+++ b/modules/ROOT/images/path_pattern_expressions.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/modules/ROOT/images/predicate_operators.svg b/modules/ROOT/images/predicate_operators.svg
new file mode 100644
index 000000000..d1cc6b308
--- /dev/null
+++ b/modules/ROOT/images/predicate_operators.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/modules/ROOT/pages/appendix/gql-conformance/additional-cypher.adoc b/modules/ROOT/pages/appendix/gql-conformance/additional-cypher.adoc
index fd877826e..536949f1f 100644
--- a/modules/ROOT/pages/appendix/gql-conformance/additional-cypher.adoc
+++ b/modules/ROOT/pages/appendix/gql-conformance/additional-cypher.adoc
@@ -69,7 +69,7 @@ Either the pattern already exists, or it needs to be created.
| Cypher feature
| Description
-| xref:values-and-types/lists.adoc#cypher-list-comprehension[List comprehension]
+| xref:expressions/list-expressions.adoc#list-comprehension[List comprehension]
| Syntactic construct for creating a `LIST` based on existing lists.
| xref:values-and-types/maps.adoc#cypher-map-comprehension[Map projection]
@@ -622,10 +622,10 @@ GQL supports `GRAPH TYPES` as a way of constraining a graph schema, but does not
| Cypher feature
| Description
-| xref:syntax/operators.adoc#query-operator-comparison-string-specific[`STARTS WITH`, `CONTAINS`, `ENDS WITH`, and regular expressions].
+| xref:expressions/predicates/string-operators.adoc[`STARTS WITH`, `CONTAINS`, `ENDS WITH`, and regular expressions].
| `STRING` comparison operators.
-| xref:syntax/operators.adoc#query-operators-list[`IN`]
+| xref:expressions/predicates/list-operators.adoc[`IN`]
| `IN` predicate for `LIST` values.
|===
diff --git a/modules/ROOT/pages/appendix/gql-conformance/supported-mandatory.adoc b/modules/ROOT/pages/appendix/gql-conformance/supported-mandatory.adoc
index 4551dd8f6..d51a1a936 100644
--- a/modules/ROOT/pages/appendix/gql-conformance/supported-mandatory.adoc
+++ b/modules/ROOT/pages/appendix/gql-conformance/supported-mandatory.adoc
@@ -28,6 +28,11 @@ The below table is instead listed in order of their appearance in the link:https
Cypher supports the boolean type predicate for `TRUE`, `FALSE`, and `NULL` but does not support the GQL keyword `UNKNOWN`.
+| 9.1
+|
+| xref:queries/combined-queries.adoc#combining-union-and-union-all[Combining `UNION` and `UNION ALL`]
+|
+
| 13.2
|
| xref:clauses/create.adoc#insert-as-synonym-of-create[`INSERT`]
@@ -123,7 +128,7 @@ This is currently not available in Cypher.
| 19.3
|
-| xref:syntax/operators.adoc##query-operators-comparison[Comparison operators]
+| xref:expressions/predicates/comparison-operators.adoc[Comparison operators]
|
| 19.4
@@ -133,22 +138,22 @@ This is currently not available in Cypher.
| 19.5
|
-| xref:values-and-types/type-predicate.adoc#type-predicate-null[Type predicate expressions for `NULL`]
+| xref:expressions/predicates/type-predicate-expressions.adoc#type-predicate-null[Type predicate expressions for `NULL`]
|
| 19.6
|
-| xref:values-and-types/type-predicate.adoc#[]
+| xref:expressions/predicates/type-predicate-expressions.adoc#[]
|
| 19.7
|
-| xref:syntax/operators.adoc#match-string-is-normalized[`IS NORMALIZED`], xref:syntax/operators.adoc#match-string-is-not-normalized[`IS NOT NORMALIZED`]
+| xref:expressions/predicates/string-operators.adoc#string-normalization-operators[`IS NORMALIZED`,`IS NOT NORMALIZED`]
|
| 20.2
|
-| xref:queries/expressions.adoc[]
+| xref:expressions/index.adoc[]
|
| 20.3
@@ -159,7 +164,7 @@ In Cypher, current user details can be seen using the link:{neo4j-docs-base-uri}
| 20.7
|
-| xref:queries/case.adoc[`CASE`], xref:functions/scalar.adoc#functions-nullIf[`nullIf()`], xref:functions/scalar.adoc#functions-coalesce[`coalesce()`]
+| xref:expressions/conditional-expressions.adoc[`CASE`], xref:functions/scalar.adoc#functions-nullIf[`nullIf()`], xref:functions/scalar.adoc#functions-coalesce[`coalesce()`]
|
| 20.9
@@ -175,7 +180,7 @@ For example, `RETURN sum()` on an empty table returns `NULL` in GQL, but i
| 20.21
|
-| xref:syntax/operators.adoc#query-operators-mathematical[Mathematical operators]
+| xref:expressions/mathematical-operators.adoc[Mathematical operators]
|
| 20.22
@@ -185,7 +190,7 @@ For example, `RETURN sum()` on an empty table returns `NULL` in GQL, but i
| 20.23
|
-| xref:syntax/operators.adoc#syntax-concatenating-two-strings-doublebar[`STRING` concatenation operator (`\|\|`)]
+| xref:expressions/string-operators.adoc[`STRING` concatenation operator (`\|\|`)]
|
| 20.24
diff --git a/modules/ROOT/pages/appendix/gql-conformance/supported-optional.adoc b/modules/ROOT/pages/appendix/gql-conformance/supported-optional.adoc
index 77defa1ec..def826ee0 100644
--- a/modules/ROOT/pages/appendix/gql-conformance/supported-optional.adoc
+++ b/modules/ROOT/pages/appendix/gql-conformance/supported-optional.adoc
@@ -85,7 +85,7 @@ These codes order the features in the table below.
| GA06
| Value type predicates
-| xref:values-and-types/type-predicate.adoc[Type predicate expressions]
+| xref:expressions/predicates/type-predicate-expressions.adoc[Type predicate expressions]
|
| GA07
@@ -116,7 +116,7 @@ Cypher only supports xref:functions/mathematical-numeric.adoc#functions-ceil[`ce
| Note the following exceptions:
* Cypher uses the xref:functions/mathematical-logarithmic.adoc#functions-log[`log()`] function instead of GQL's `LN()` function.
-* Cypher uses the xref:syntax/operators.adoc#syntax-using-the-exponentiation-operator[exponentiation operator (`^`)] instead of GQL's `POWER()` function.
+* Cypher uses the xref:expressions/mathematical-operators.adoc[exponentiation operator (`^`)] instead of GQL's `POWER()` function.
| GF05
| Multi-character trim functions
@@ -158,7 +158,7 @@ For example, GQL’s graph reference values `CURRENT_GRAPH` and `CURRENT_PROPERT
| GQ03
| Composite query: `UNION`
-| xref:clauses/union.adoc[`UNION`]
+| xref:queries/combined-queries.adoc[`UNION`]
|
| GQ13
@@ -199,12 +199,12 @@ GQL also defines a parameterless version of the function not in Cypher: `CURRENT
| GV66
| Open dynamic unions
-| xref:values-and-types/type-predicate.adoc#type-predicate-any-and-nothing[Type predicate expressions -> `ANY` and `NOTHING`]
+| xref:expressions/predicates/type-predicate-expressions.adoc#type-predicate-any-and-nothing[Type predicate expressions -> `ANY` and `NOTHING`]
|
| GV67
| Closed dynamic unions
-| xref:values-and-types/type-predicate.adoc#type-predicate-closed-dynamic-unions[Closed dynamic unions]
+| xref:expressions/predicates/type-predicate-expressions.adoc#type-predicate-closed-dynamic-unions[Closed dynamic unions]
|
| GV70
@@ -214,7 +214,7 @@ GQL also defines a parameterless version of the function not in Cypher: `CURRENT
| GV71
| Immaterial value types: empty type support (`NOTHING`)]
-| xref:values-and-types/type-predicate.adoc#type-predicate-any-and-nothing[Type predicate expressions -> `ANY` and `NOTHING`]
+| xref:expressions/predicates/type-predicate-expressions.adoc#type-predicate-any-and-nothing[Type predicate expressions -> `ANY` and `NOTHING`]
|
|===
diff --git a/modules/ROOT/pages/clauses/clause-composition.adoc b/modules/ROOT/pages/clauses/clause-composition.adoc
index fa560590f..660bab810 100644
--- a/modules/ROOT/pages/clauses/clause-composition.adoc
+++ b/modules/ROOT/pages/clauses/clause-composition.adoc
@@ -297,7 +297,7 @@ the graph made by the `CREATE`.
[[cypher-clause-composition-union-queries]]
== Queries with `UNION`
-xref::clauses/union.adoc[`UNION`] queries are slightly different because the results of two or more queries are put together,
+xref::queries/combined-queries.adoc[`UNION`] queries are slightly different because the results of two or more queries are put together,
but each query starts with an empty table of intermediate results.
In a query with a `UNION` clause, any clause _before_ the `UNION` cannot observe writes made by a clause _after_ the `UNION`.
diff --git a/modules/ROOT/pages/clauses/index.adoc b/modules/ROOT/pages/clauses/index.adoc
index abb25fab2..9a8029e51 100644
--- a/modules/ROOT/pages/clauses/index.adoc
+++ b/modules/ROOT/pages/clauses/index.adoc
@@ -155,12 +155,12 @@ Typically used when modifying or importing large amounts of data.
|===
|Clause |Description
-m| xref::clauses/union.adoc[UNION]
+m| xref::queries/combined-queries.adoc[UNION]
a|
Combines the result of multiple queries into a single result set.
Duplicates are removed.
-m| xref::clauses/union.adoc[UNION ALL]
+m| xref::queries/combined-queries.adoc[UNION ALL]
a|
Combines the result of multiple queries into a single result set.
Duplicates are retained.
diff --git a/modules/ROOT/pages/clauses/match.adoc b/modules/ROOT/pages/clauses/match.adoc
index 3dffc1a0c..861850161 100644
--- a/modules/ROOT/pages/clauses/match.adoc
+++ b/modules/ROOT/pages/clauses/match.adoc
@@ -387,7 +387,7 @@ RETURN p.name AS actor, r.role AS role
----
[NOTE]
-The above query uses the xref:syntax/operators.adoc#query-operator-comparison-string-specific[`CONTAINS` operator].
+The above query uses the xref:expressions/predicates/string-operators.adoc[`CONTAINS` operator].
.Result
[role="queryresult",options="header,footer",cols="2*
RETURN n.name, keys(n);
----
-<1> The xref:functions/list.adoc#functions-keys[keys()] function retrieves all property keys of the matched nodes, and a xref:values-and-types/lists.adoc#cypher-list-comprehension[list comprehension] filters these keys to include only those that contain the substring "Test", assigning the resulting list to the variable `propertyKeys`.
+<1> The xref:functions/list.adoc#functions-keys[keys()] function retrieves all property keys of the matched nodes, and a xref:expressions/list-expressions.adoc#list-comprehension[list comprehension] filters these keys to include only those that contain the substring "Test", assigning the resulting list to the variable `propertyKeys`.
<2> The xref:clauses/foreach.adoc[`FOREACH`] clause iterates over each key in the `propertyKeys` list and removes the corresponding property using the `REMOVE` clause.
All properties with the word "Test" in them are removed:
diff --git a/modules/ROOT/pages/clauses/where.adoc b/modules/ROOT/pages/clauses/where.adoc
index 9a3bb0c25..bd5c42260 100644
--- a/modules/ROOT/pages/clauses/where.adoc
+++ b/modules/ROOT/pages/clauses/where.adoc
@@ -1,201 +1,112 @@
:description: `WHERE` adds constraints to the patterns in a `MATCH` or `OPTIONAL MATCH` clause or filters the results of a `WITH` clause.
-
-[[query-where]]
+:table-caption!:
= WHERE
-[[where-introduction]]
-== Introduction
-
-The `WHERE` clause is not a clause in its own right -- rather, it is part of the `MATCH`, `OPTIONAL MATCH`, and `WITH` clauses.
+The `WHERE` clause is not a clause in its own right -- rather, it is subclause used with xref:clauses/match.adoc[`MATCH`], xref:clauses/optional-match.adoc[`OPTIONAL MATCH`], and xref:clauses/with.adoc[`WITH`] clauses.
When used with `MATCH` and `OPTIONAL MATCH`, `WHERE` adds constraints to the patterns described.
_It should not be seen as a filter after the matching is finished._
-In the case of `WITH`, however, `WHERE` simply filters the results.
-
In the case of multiple `MATCH` / `OPTIONAL MATCH` clauses, the predicate in `WHERE` is always a part of the patterns in the directly preceding `MATCH` / `OPTIONAL MATCH`.
Both results and performance may be impacted if `WHERE` is put inside the wrong `MATCH` clause.
-xref:indexes/search-performance-indexes/managing-indexes.adoc[Indexes] may be used to optimize queries using `WHERE` in a variety of cases.
+When used after `WITH`, `WHERE` simply filters the results.
+
+[TIP]
+For more uses of `WHERE`, see xref:expressions/predicates/index.adoc[].
[[where-example-graph]]
== Example graph
The following graph is used for the examples below:
-image::graph_where_clause.svg[width="600",role="middle"]
+image::graph_where_clause.svg[width="700",role="middle"]
To recreate the graph, run the following query in an empty Neo4j database:
[source, cypher, role=test-setup]
----
-CREATE
-(andy:Swedish:Person {name: 'Andy', age: 36, belt: 'white'}),
-(timothy:Person {name: 'Timothy', age: 25}),
-(peter:Person {name: 'Peter', age: 35, email: 'peter_n@example.com'}),
-(andy)-[:KNOWS {since: 2012}]->(timothy),
-(andy)-[:KNOWS {since: 1999}]->(peter)
-----
-
-[[query-where-basic]]
-== Basic usage
-
-[[node-pattern-predicates]]
-=== Node pattern predicates
-
-`WHERE` can appear inside a node pattern in a `MATCH` clause or a pattern comprehension:
-
-.Query
-// tag::clauses_where_in_match_clause[]
-[source, cypher]
-----
-WITH 30 AS minAge
-MATCH (a:Person WHERE a.name = 'Andy')-[:KNOWS]->(b:Person WHERE b.age > minAge)
-RETURN b.name
-----
-// end::clauses_where_in_match_clause[]
-
-.Result
-[role="queryresult",options="header,footer",cols="1*(b WHERE b:Person) | b.name] AS friends
-----
-// end::clauses_where_pattern_comprehension[]
-
-.Result
-[role="queryresult",options="header,footer",cols="1*(timothy),
+ (andy)-[:KNOWS {since: 1999}]->(peter),
+ (peter)-[:KNOWS {since: 2005}]->(lisa),
+ (lisa)-[:KNOWS {since: 2010}]->(john),
+ (john)-[:KNOWS {since: 2021}]->(susan)
----
-// end::clauses_where_boolean_operations[]
-.Result
-[role="queryresult",options="header,footer",cols="2*(f)
+MATCH (:Person {name:'Andy'})-[k:KNOWS]->(f)
WHERE k.since < 2000
-RETURN f.name, f.age, f.email
+RETURN f.name AS oldFriend
----
// end::clauses_where_relationship_property[]
-The `name`, `age` and `email` values for `Peter` are returned because `Andy` has known him since before 2000:
-
.Result
-[role="queryresult",options="header,footer",cols="3* 40
+RETURN n.name AS name, n.age AS age
----
-
-The `name` and `age` values for `Timothy` are returned because he is less than 30 years of age:
+// end::clauses_where_dynamic[]
.Result
[role="queryresult",options="header,footer",cols="2*(b:Person WHERE b.age > minAge)
+RETURN b.name AS name
----
-
-The given `STRING` values contain only normalized Unicode characters, therefore all the matched `name` properties are returned.
-For more information, see the section about the xref:syntax/operators.adoc#match-string-is-normalized[normalization operator].
+// end::clauses_where_node_pattern[]
.Result
[role="queryresult",options="header,footer",cols="1*(b WHERE b:Person) | b.name] AS friends
----
-
-The `name` and `age` values for `Timothy` are returned because his name starts with "Tim".
+// end::clauses_where_pattern_comprehension[]
.Result
-[role="queryresult",options="header,footer",cols="2*(b:Person)
+RETURN a.name AS person, b.name AS friend, r.since AS knowsSince
----
-The `name`, `age`, and `email` values for `Peter` are returned because his email ends with ".com":
-
.Result
[role="queryresult",options="header,footer",cols="3*(timothy)
-RETURN other.name, other.age
-----
-// end::clauses_where_patterns[]
-
-The `name` and `age` values for nodes that have an outgoing relationship to `Timothy` are returned:
-
-.Result
-[role="queryresult",options="header,footer",cols="2*(peter)
-RETURN other.name, other.age
-----
-
-The `name` and `age` values for nodes that do not have an outgoing relationship to `Peter` are returned:
-
-.Result
-[role="queryresult",options="header,footer",cols="2*(b:Person) | r.since] AS years
----
-This returns all values for all nodes, even those without the `belt` property:
-
.Result
-[role="queryresult",options="header,footer",cols="3*
-| "Timothy" | 25 |
-3+|Rows: 3
+[role="queryresult",options="header,footer",cols="1*
-3+|Rows: 1
+1+d|Rows: 1
|===
+[[variable-length-patterns]]
+=== Variable-length patterns
-[[query-where-ranges]]
-== Using ranges
-
-[[simple-range]]
-=== Simple range
+If matching for variable length patterns, `WHERE` can only be used together with the xref:patterns/variable-length-patterns.adoc#quantified-path-patterns[quantified path pattern] or xref:patterns/variable-length-patterns.adoc#quantified-relationships[quantified relationships] syntax.
-To check whether an element exists within a specific range, use the inequality operators `<`, `<=`, `>=`, `>`:
-
-.Query
+.Allowed - `WHERE` predicate inside a quantified relationship
+// tag::clauses_where_var_length[]
[source, cypher]
----
-MATCH (a:Person)
-WHERE a.name >= 'Peter'
-RETURN a.name, a.age
+MATCH p = (a:Person {name: "Andy"})-[r:KNOWS WHERE r.since < 2011]->{1,4}(:Person)
+RETURN [n IN nodes(p) | n.name] AS paths
----
+// end::clauses_where_var_length[]
-The `name` and `age` values of nodes having a `name` property lexicographically (i.e. using the dictionary order) greater than or equal to `Peter` are returned:
+Note that any paths including `Timothy` and `Susan` are excluded by the `WHERE` predicate, since their incoming `KNOWS` relationships both have a `since` value that is higher than `2011.`
.Result
-[role="queryresult",options="header,footer",cols="2* 'Andy' AND a.name < 'Timothy'
-RETURN a.name, a.age
-----
-
-The `name` and `age` values of nodes having a `name` property lexicographically between `Andy` and `Timothy` are returned:
-
-.Result
-[role="queryresult",options="header,footer",cols="2*(b:Person)
-RETURN r.since
-----
-
-.Result
-[role="queryresult",options="header,footer",cols="1* b.yearOfBirth]->(b:Person)
-RETURN r.since
-----
-
-.Error message
-[source, output]
-----
-Relationship pattern predicates are not supported for variable-length relationships.
-----
-
-
-Putting predicates inside a relationship pattern can help with readability.
-Note that it is strictly equivalent to using a standalone `WHERE` sub-clause.
-
-.Query
-[source, cypher]
-----
-WITH 2000 AS minYear
-MATCH (a:Person)-[r:KNOWS]->(b:Person)
-WHERE r.since < minYear
-RETURN r.since
-----
-
-.Result
-[role="queryresult",options="header,footer",cols="1*(b:Person) | r.since] AS years
+MATCH p = (a:Person {name: 'Andy'})-[r:KNOWS*1..4 WHERE r.since < 2011]->(b:Person)
+RETURN [n IN nodes(p) | n.name] AS path
----
-
-.Result
-[role="queryresult",options="header,footer",cols="1*
----
a|
-Extended xref:values-and-types/type-predicate.adoc[type predicate expressions].
+Extended xref:expressions/predicates/type-predicate-expressions.adoc[type predicate expressions].
Closed dynamic union types (`type1 \| type2 \| ...`) are now supported. For example, the following query which evaluates to true if a value is either of type `INTEGER` or `FLOAT`:
[source, cypher, role="noheader"]
@@ -1548,7 +1547,7 @@ IS [NOT] ::
----
a|
-Extended xref:values-and-types/type-predicate.adoc[type predicate expressions].
+Extended xref:expressions/predicates/type-predicate-expressions.adoc[type predicate expressions].
The newly supported types are:
* `NOTHING`
@@ -1722,7 +1721,7 @@ IS [NOT] ::
----
a|
-Added xref:values-and-types/type-predicate.adoc[type predicate expressions].
+Added xref:expressions/predicates/type-predicate-expressions.adoc[type predicate expressions].
The available types are:
* `BOOLEAN`
@@ -5040,7 +5039,7 @@ label:removed[]
extract()
----
a|
-Replaced by xref:values-and-types/lists.adoc#cypher-list-comprehension[list comprehension].
+Replaced by xref:expressions/list-expressions.adoc#list-comprehension[list comprehension].
a|
label:function[]
@@ -5050,7 +5049,7 @@ label:removed[]
filter()
----
a|
-Replaced by xref:values-and-types/lists.adoc#cypher-list-comprehension[list comprehension].
+Replaced by xref:expressions/list-expressions.adoc#list-comprehension[list comprehension].
a|
label:functionality[]
@@ -5415,7 +5414,7 @@ label:deprecated[]
extract()
----
a|
-Replaced by xref:values-and-types/lists.adoc#cypher-list-comprehension[list comprehension].
+Replaced by xref:expressions/list-expressions.adoc#list-comprehension[list comprehension].
a|
label:function[]
@@ -5425,7 +5424,7 @@ label:deprecated[]
filter()
----
a|
-Replaced by xref:values-and-types/lists.adoc#cypher-list-comprehension[list comprehension].
+Replaced by xref:expressions/list-expressions.adoc#list-comprehension[list comprehension].
|===
@@ -5440,7 +5439,7 @@ Replaced by xref:values-and-types/lists.adoc#cypher-list-comprehension[list comp
| xref:functions/scalar.adoc#functions-randomuuid[randomUUID()] | Function | Added |
| xref:values-and-types/temporal.adoc[Temporal types] | Functionality | Added | Supports storing, indexing and working with the following temporal types: Date, Time, LocalTime, DateTime, LocalDateTime and Duration.
| xref:functions/temporal/index.adoc[Temporal functions] | Functionality | Added | Functions allowing for the creation and manipulation of values for each temporal type -- _Date_, _Time_, _LocalTime_, _DateTime_, _LocalDateTime_ and _Duration_.
-| xref:syntax/operators.adoc#query-operators-temporal[Temporal operators] | Functionality | Added | Operators allowing for the manipulation of values for each temporal type -- _Date_, _Time_, _LocalTime_, _DateTime_, _LocalDateTime_ and _Duration_.
+| xref:expressions/temporal-operators.adoc[Temporal operators] | Functionality | Added | Operators allowing for the manipulation of values for each temporal type -- _Date_, _Time_, _LocalTime_, _DateTime_, _LocalDateTime_ and _Duration_.
| xref:functions/string.adoc#functions-tostring[toString()] | Function | Extended | Now also allows temporal values as input (i.e. values of type _Date_, _Time_, _LocalTime_, _DateTime_, _LocalDateTime_ or _Duration_).
|===
diff --git a/modules/ROOT/pages/queries/case.adoc b/modules/ROOT/pages/expressions/conditional-expressions.adoc
similarity index 88%
rename from modules/ROOT/pages/queries/case.adoc
rename to modules/ROOT/pages/expressions/conditional-expressions.adoc
index 1dae13b99..d68734489 100644
--- a/modules/ROOT/pages/queries/case.adoc
+++ b/modules/ROOT/pages/expressions/conditional-expressions.adoc
@@ -15,7 +15,7 @@ Two variants of `CASE` exist within Cypher: the _simple_ form, to compare a sing
The following graph is used for the examples below:
-image:case_graph.svg[width="500",role="middle"]
+image::case_graph.svg[width="400",role="middle"]
To recreate the graph, run the following query against an empty Neo4j database:
@@ -75,6 +75,7 @@ END
[[case-simple-examples]]
=== Example
+// tag::expressions_conditional_expressions_simple[]
[source, cypher]
----
MATCH (n:Person)
@@ -85,6 +86,8 @@ CASE n.eyes
ELSE 3
END AS result, n.eyes
----
+// end::expressions_conditional_expressions_simple[]
+
[role="queryresult",options="header,footer",cols="2*+`, `+<+`, `+>+`, `+<=+`, `+>=+`
-* xref:values-and-types/working-with-null.adoc#is-null-is-not-null[`IS NULL` Operator]: `IS [NOT] NULL`
-* xref:values-and-types/type-predicate.adoc[Type Predicate Expression]: `IS [NOT] TYPED ` (Note that the form `IS [NOT] :: ` is not accepted)
-* xref::syntax/operators.adoc#match-string-is-normalized[Normalization Predicate Expression]: `IS [NOT] NORMALIZED`
-* xref::syntax/operators.adoc#query-operator-comparison-string-specific[String Comparison Operators]: `STARTS WITH`, `ENDS WITH`, `=~` (regex matching)
+* xref:expressions/predicates/comparison-operators.adoc[Regular Comparison Operators]: `+=+`, `+<>+`, `+<+`, `+>+`, `+<=+`, `+>=+`
+* xref:expressions/predicates/comparison-operators.adoc[`IS [NOT] NULL`]
+* xref:expressions/predicates/type-predicate-expressions.adoc[Type predicate expressions]: `IS [NOT] TYPED ` (Note that the form `IS [NOT] :: ` is not accepted)
+* xref:expressions/predicates/string-operators.adoc[Normalization Predicate Expression]: `IS [NOT] NORMALIZED`
+* xref:expressions/predicates/string-operators.adoc[String Comparison Operators]: `STARTS WITH`, `ENDS WITH`, `=~` (regex matching)
+
=== Syntax
@@ -147,6 +151,7 @@ END
[[case-extended-simple-examples]]
=== Example
+// tag::expressions_conditional_expressions_extended_simple[]
[source, cypher]
----
MATCH (n:Person)
@@ -161,6 +166,7 @@ CASE n.age
ELSE "Adult"
END AS result
----
+// end::expressions_conditional_expressions_extended_simple[]
[role="queryresult",options="header,footer",cols="2*`, `<`, `>`, `\<=`, `>=`, `IS NULL`, `IS NOT NULL`
+** xref:expressions/predicates/list-operators.adoc[]: `IN`
+** xref:expressions/predicates/string-operators.adoc[]: `STARTS WITH`, `ENDS WITH`, `CONTAINS`, `IS NORMALIZED`, `IS NOT NORMALIZED`, `=~`
+** xref:expressions/predicates/path-pattern-expressions.adoc[]: information about filtering queries with path pattern expressions.
+** xref:expressions/predicates/type-predicate-expressions.adoc[]: information about how to verify the value type of a Cypher expression.
+* xref:expressions/node-relationship-operators.adoc[]: information about how to access `NODE` and `RELATIONSHIP` property values with `.` and `[]`.
+* xref:expressions/mathematical-operators.adoc[]: `+`, `-`, `*`, `/`, `%`, `^`.
+* xref:expressions/string-operators.adoc[]: `+`, `||`
+* xref:expressions/temporal-operators.adoc[]: `+`, `-`, `*`, `/`
+* xref:expressions/list-expressions.adoc[]: information about list concatenation operators (`||`, `+`), list element access, list slicing, and list as well as pattern comprehensions.
+* xref:expressions/map-expressions.adoc[]: information about map operators (`.`, `[]`) and map projection.
+* xref:expressions/conditional-expressions.adoc[]
+
+The following expressions are documented elsewhere in the Cypher Manual:
+
+* xref:patterns/reference.adoc#label-expressions[Label expressions]
+* xref:functions/index.adoc[Function calls]
+* Subquery expressions: xref:subqueries/collect.adoc[`COLLECT`], xref:subqueries/count.adoc[`COUNT`], and xref:subqueries/existential.adoc[`EXISTS`]
+* Value literals (see xref:values-and-types/index.adoc[])
+
+[NOTE]
+Expressions containing unsanitized user input may make your application vulnerable to Cypher injection.
+Consider using xref:syntax/parameters.adoc[parameters] instead.
+For more information, see link:https://neo4j.com/developer/kb/protecting-against-cypher-injection/[Neo4j Knowledge Base -> Protecting against Cypher Injection].
+
diff --git a/modules/ROOT/pages/expressions/list-expressions.adoc b/modules/ROOT/pages/expressions/list-expressions.adoc
new file mode 100644
index 000000000..2426d776b
--- /dev/null
+++ b/modules/ROOT/pages/expressions/list-expressions.adoc
@@ -0,0 +1,674 @@
+= List expressions
+:description: Information about Cypher's list expressions.
+:table-caption!:
+
+List expressions allow you to manipulate and query xref:values-and-types/lists.adoc[`LIST`] values in Cypher.
+
+For more expressions that evaluate to a `LIST` value, see xref:functions/list.adoc[List functions]. +
+For information about how to check membership in a `LIST` using the `IN` operator, see xref:expressions/predicates/list-operators.adoc[Predicates -> List operators].
+
+[[example-graph]]
+== Example graph
+
+The following graph is used for the examples below:
+
+image::list_expressions_graph.svg[width="700",role="middle"]
+
+To recreate the graph, run the following query against an empty Neo4j database:
+
+[source, cypher]
+----
+CREATE (alice:Person {name:'Alice', age: 65, role: 'Project manager', skills: ['Java', 'Python']}),
+ (cecil:Person {name: 'Cecil', age: 25, role: 'Software developer', skills: ['Java', 'Python']}),
+ (cecilia:Person {name: 'Cecilia', age: 31, role: 'Software developer', skills: ['JavaScript', 'TypeScript']}),
+ (charlie:Person {name: 'Charlie', age: 61, role: 'Security engineer', skills: ['C++', 'Python']}),
+ (daniel:Person {name: 'Daniel', age: 39, role: 'Director', skills: ['Ruby', 'Go']}),
+ (eskil:Person {name: 'Eskil', age: 39, role: 'CEO', skills: ['Java', 'C++', 'Python']}),
+
+ (cecil)-[:WORKS_FOR]->(alice),
+ (cecilia)-[:WORKS_FOR]->(alice),
+ (charlie)-[:WORKS_FOR]->(daniel),
+ (alice)-[:WORKS_FOR]->(daniel),
+ (daniel)-[:WORKS_FOR]->(eskil)
+----
+
+
+[[list-element-access]]
+== List element access
+
+The subscript operator, `[]`, can be used to access specific elements in a `LIST`.
+`[0]` refers to the first element in a `LIST`, `[1]` to the second, and so on.
+`[-1]` refers to the last element in a `LIST`, `[-2]` to the penultimate element, and so on.
+
+.Access individual elements in a `LIST`
+// tag::expressions_list_element_access[]
+[source, cypher]
+----
+WITH [1, 2, 3, 4] AS list
+RETURN list[0] AS firstElement,
+ list[2] AS thirdElement,
+ list[-1] AS finalElement
+----
+// end::expressions_list_element_access[]
+
+.Result
+[role="queryresult",options="header,footer",cols="3* 2 | n] AS filteredList
+----
+// end::expressions_list_comprehension[]
+
+.Result
+[role="queryresult",options="header,footer",cols="1*(alice) | employee.name] AS employees
+----
+// end::expressions_list_pattern_comprehension[]
+
+.Result
+[role="queryresult",options="header,footer",cols="1*(alice) WHERE employee.age > 30 | employee.name || ', ' || toString(employee.age)] AS employeesAbove30
+----
+// end::expressions_list_pattern_comprehension_where[]
+
+.Result
+[role="queryresult",options="header,footer",cols="1*+(superior:Person) | superior.skills] AS superiorsSkills
+----
+
+Pattern comprehension only supports only the xref:patterns/reference.adoc#variable-length-relationships[variable-length relationships] syntax.
+The below query uses a pattern comprehension to collect the skills of all superiors in the chain above `Cecil`.
+The xref:functions/list.adoc#functions-reduce[`reduce()`] function concatenates these skills into a single `LIST`, and xref:clauses/unwind.adoc[`UNWIND`] is used to flatten this `LIST` before returning the distinct skills in a new `LIST`.
+
+.Allowed: variable-length pattern comprehension using variable-length relationship syntax
+// tag::expressions_list_pattern_comprehension_var_length[]
+[source, cypher]
+----
+MATCH (cecil:Person {name: 'Cecil'})
+WITH [(cecil)-[:WORKS_FOR*]->(superior:Person) | superior.skills] AS allSuperiorsSkills
+WITH reduce(accumulatedSkills = [], superiorSkills IN allSuperiorsSkills | accumulatedSkills || superiorSkills) AS allSkills
+UNWIND allSkills AS superiorsSkills
+RETURN collect(DISTINCT superiorsSkills) AS distinctSuperiorsSkills
+----
+// end::expressions_list_pattern_comprehension_var_length[]
+
+.Result
+[role="queryresult",options="header,footer",cols="1*(theMatrix),
+ (keanu)-[:ACTED_IN]->(theMatrixRevolutions),
+ (keanu)-[:ACTED_IN]->(theMatrixReloaded),
+ (keanu)-[:ACTED_IN]->(theMatrixResurrections),
+ (keanu)-[:ACTED_IN]->(theDevilsAdvocate),
+
+ (carrieAnne)-[:ACTED_IN]->(theMatrix),
+ (carrieAnne)-[:ACTED_IN]->(theMatrixRevolutions),
+ (carrieAnne)-[:ACTED_IN]->(theMatrixReloaded),
+ (carrieAnne)-[:ACTED_IN]->(theMatrixResurrections)
+----
+
+[[map-operators]]
+== Map operators
+
+Cypher contains two map operators:
+
+* Statically access a value by key: dot operator (`.`).
+* Dynamically access a value by key: subscript operator (`[]`).
+
+[[static-map-access]]
+=== Statically access a `MAP` value
+
+`MAP` values can be accessed statically by specifying a key after the `.` operator.
+
+.Static `MAP` value access
+// tag::expressions_map_static_access[]
+[source, cypher]
+----
+WITH {a: 10, b: 20, c: 30} AS map
+RETURN map.a AS firstValue,
+ map.c AS lastValue
+----
+// end::expressions_map_static_access[]
+
+.Result
+[role="queryresult",options="header,footer",cols="2*(m:Movie)
+RETURN p.name AS actor, collect(m{.title, .released}) AS movies
+----
+
+.Result
+[role="queryresult",options="header,footer",cols="2*(movie:Movie)
+WITH keanu, collect(movie) AS movies
+RETURN keanu {.name, totalMovies: size(movies)} AS keanuDetails
+----
+
+.Result
+[role="queryresult",options="header,footer",cols="1*(movie:Movie)
+WITH actor, count(movie) AS totalMovies
+RETURN actor{totalMovies, .name} AS nameAndMovies
+----
+
+.Result
+[role="queryresult",options="header,footer",cols="1*(alice),
+ (cecilia)-[:WORKS_FOR {since: 2015}]->(alice)
+----
+
+[[static-property-access]]
+== Static property access
+
+Property values can be accessed statically by specifying a property name after the `.` operator.
+
+.Access node properties statically
+[source, cypher]
+----
+MATCH (p:Person)
+RETURN p.firstName AS name
+----
+
+.Result
+[role="queryresult",options="header,footer",cols="1*(manager:Person)
+RETURN employee.firstName AS employee,
+ r.since AS employedSince,
+ manager.firstName AS manager
+----
+// end::expressions_node_relationship_operators_static_property_access[]
+
+.Result
+[role="queryresult",options="header,footer",cols="3* 30 AND n.role = 'Software developer'
+RETURN n.name AS name, n.age AS age, n.role AS role
+----
+// end::expressions_predicates_boolean_operators_and[]
+
+.Result
+[role="queryresult",options="header,footer",cols="3* 30 XOR n.role = 'Software developer'
+RETURN n.name AS name, n.age AS age, n.role AS role
+----
+// end::expressions_predicates_boolean_operators_xor[]
+
+.Result
+[role="queryresult",options="header,footer",cols="3* 60 AND n.role = 'Security engineer') OR NOT (n.role = 'Director' OR n.name = 'Eskil')
+RETURN n.name AS name, n.age AS age, n.role AS role
+----
+
+.Result
+[role="queryresult",options="header,footer",cols="3*`
+* Less than: `<`
+* Greater than: `>`
+* Less than or equal to: `\<=`
+* Greater than or equal to: `>=`
+* `IS NULL`
+* `IS NOT NULL`
+
+[TIP]
+For more information about how Cypher orders and compares different value types, see xref:values-and-types/ordering-equality-comparison.adoc[Values and types -> Equality, ordering, and comparison of value types]
+
+
+[[example-graph]]
+== Example graph
+
+The following graph is used for the examples below:
+
+image::predicate_operators.svg[width="500",role="middle"]
+
+To recreate the graph, run the following query in an empty Neo4j database:
+
+[source, cypher, role=test-setup]
+----
+CREATE (alice:Person {name:'Alice', age: 65, role: 'Project manager', email: 'alice@company.com'}),
+ (cecil:Person {name: 'Cecil', age: 25, role: 'Software developer', email: 'cecil@private.se'}),
+ (cecilia:Person {name: 'Cecilia', age: 31, role: 'Software developer'}),
+ (charlie:Person {name: 'Charlie', age: 61, role: 'Security engineer'}),
+ (daniel:Person {name: 'Daniel', age: 39, role: 'Director', email: 'daniel@company.com'}),
+ (eskil:Person {name: 'Eskil', age: 39, role: 'CEO', email: 'eskil@company.com'})
+----
+
+[[examples]]
+== Examples
+
+.Comparison operators
+=====
+
+.Equality operator (`=`)
+// tag::expressions_predicates_comparison_operators_equality[]
+[source, cypher]
+----
+MATCH (n:Person)
+WHERE n.role = 'Software developer'
+RETURN n.name AS name, n.role AS role
+----
+// end::expressions_predicates_comparison_operators_equality[]
+
+.Result
+[role="queryresult",options="header,footer",cols="2*`)
+// tag::expressions_predicates_comparison_operators_inequality[]
+[source, cypher]
+----
+MATCH (n:Person)
+WHERE n.role <> 'Software developer'
+RETURN n.name AS name, n.role AS role
+----
+// end::expressions_predicates_comparison_operators_inequality[]
+
+.Result
+[role="queryresult",options="header,footer",cols="2*`)
+// tag::expressions_predicates_comparison_operators_greater_than[]
+[source, cypher]
+----
+MATCH (n:Person)
+WHERE n.age > 39
+RETURN n.name AS name, n.age AS age
+----
+// end::expressions_predicates_comparison_operators_greater_than[]
+
+.Result
+[role="queryresult",options="header,footer",cols="2*=`)
+// tag::expressions_predicates_comparison_operators_greater_than_or_equal[]
+[source, cypher]
+----
+MATCH (n:Person)
+WHERE n.age >= 39
+RETURN n.name AS name, n.age AS age
+----
+// end::expressions_predicates_comparison_operators_greater_than_or_equal[]
+
+.Result
+[role="queryresult",options="header,footer",cols="2* z`, `x` and `z` are not compared.
+
+[[chaining-equality-operators]]
+=== Chaining equality operators
+
+Chains of `=` and `<>` are treated in a special way in Cypher.
+Specifically, `1=1=true` is equivalent to `1=1 AND 1=true` and not to `(1=1)=true` or `1=(1=true)`.
+For example, the following expressions are equivalent.
+
+.Equivalent expressions
+[source, syntax, role=noplay]
+----
+a < b = c <= d <> e;
+a < b AND b = c AND c <= d AND d <> e
+----
diff --git a/modules/ROOT/pages/expressions/predicates/index.adoc b/modules/ROOT/pages/expressions/predicates/index.adoc
new file mode 100644
index 000000000..7ca49610d
--- /dev/null
+++ b/modules/ROOT/pages/expressions/predicates/index.adoc
@@ -0,0 +1,20 @@
+= Predicates
+:Description: Overview of the predicate expressions in Cypher.
+
+Predicates evaluate to a `BOOLEAN` value (`TRUE`, `FALSE`, or `NULL`), and are frequently used for filtering in xref:clauses/where.adoc[`WHERE`] subclauses.
+
+This chapter is divided into the following sections:
+
+* xref:expressions/predicates/boolean-operators.adoc[]: `AND`, `OR`, `XOR`, `NOT`
+* xref:expressions/predicates/comparison-operators.adoc[]: `=`, `<>`, `<`, `>`, `\<=`, `>=`, `IS NULL`, `IS NOT NULL`
+* xref:expressions/predicates/list-operators.adoc[]: `IN`
+* xref:expressions/predicates/string-operators.adoc[]: `STARTS WITH`, `ENDS WITH`, `CONTAINS`, `IS NORMALIZED`, `IS NOT NORMALIZED`, `=~`
+* xref:expressions/predicates/path-pattern-expressions.adoc[]: information about filtering queries with path pattern expressions.
+* xref:expressions/predicates/type-predicate-expressions.adoc[]: information about how to verify the value type of a Cypher expression.
+
+The following can also serve as a predicates if they result in a `BOOLEAN` value (but are documented elsewhere):
+
+* xref:syntax/variables.adoc[]
+* xref:queries/concepts.adoc[Properties] (See also xref:values-and-types/property-structural-constructed.adoc#property-types[Values and types -> property types])
+* xref:functions/predicate.adoc[Predicate functions]
+* xref:expressions/conditional-expressions.adoc[]
diff --git a/modules/ROOT/pages/expressions/predicates/list-operators.adoc b/modules/ROOT/pages/expressions/predicates/list-operators.adoc
new file mode 100644
index 000000000..78bd021c8
--- /dev/null
+++ b/modules/ROOT/pages/expressions/predicates/list-operators.adoc
@@ -0,0 +1,281 @@
+= List operators
+:description: Information about Cypher's list operators.
+:table-caption!:
+
+List operators are used to perform operations on xref:values-and-types/lists.adoc[`LIST`] values.
+Cypher contains the following list operator:
+
+* Membership: `IN`
+
+For additional list predicates, see:
+
+* The following predicate functions: xref:functions/predicate.adoc#functions-all[`all()`], xref:functions/predicate.adoc#functions-any[`any()`], xref:functions/predicate.adoc#functions-none[`none()`], and xref:functions/predicate.adoc#functions-single[`single()`].
+* The xref:functions/predicate.adoc#functions-isempty[`isEmpty()`] function.
+
+[[example-graph]]
+== Example graph
+
+The following graph is used for the examples below:
+
+image::predicate_operators.svg[width="500",role="middle"]
+
+To recreate the graph, run the following query in an empty Neo4j database:
+
+[source, cypher, role=test-setup]
+----
+CREATE (alice:Person {name:'Alice', age: 65, role: 'Project manager', email: 'alice@company.com'}),
+ (cecil:Person {name: 'Cecil', age: 25, role: 'Software developer', email: 'cecil@private.se'}),
+ (cecilia:Person {name: 'Cecilia', age: 31, role: 'Software developer'}),
+ (charlie:Person {name: 'Charlie', age: 61, role: 'Security engineer'}),
+ (daniel:Person {name: 'Daniel', age: 39, role: 'Director', email: 'daniel@company.com'}),
+ (eskil:Person {name: 'Eskil', age: 39, role: 'CEO', email: 'eskil@company.com'})
+----
+
+== Examples
+
+.Basic `LIST` membership checks
+=====
+
+.`IN` operator
+// tag::expressions_predicates_list_operators_in[]
+[source, cypher]
+----
+MATCH (n:Person)
+WHERE n.role IN ['Software developer', 'Project manager']
+RETURN n.name AS name, n.role AS role
+----
+// end::expressions_predicates_list_operators_in[]
+
+.Result
+[role="queryresult",options="header,footer",cols="2*(alice),
+ (cecilia)-[:WORKS_FOR {since: 2015}]->(alice)
+----
+
+[[filter-on-patterns]]
+== Examples
+
+.Simple path pattern expression
+// tag::expressions_predicates_path_pattern_expression[]
+[source, cypher]
+----
+MATCH (employee:Person)
+WHERE (employee)-[:WORKS_FOR]->(:Person {name: 'Alice'})
+RETURN employee.name AS employee
+----
+// end::expressions_predicates_path_pattern_expression[]
+
+.Result
+[role="queryresult",options="header,footer",cols="1*(:Person {name: 'Alice'})
+RETURN employee.name AS employee
+----
+// end::expressions_predicates_path_pattern_expression_boolean[]
+
+
+.Result
+[role="queryresult",options="header,footer",cols="1* Boolean operators].
+
+Patterns can be placed inside expressions.
+
+.Pattern inside an expression
+[source, cypher]
+----
+RETURN NOT (:Person {name: "Alice"})<-[:WORKS_FOR {since: 2023}]-(:Person) AS patternCheck
+----
+
+.Result
+[role="queryresult",options="header,footer",cols="1*(:Person {name: "Alice"})) AS patternCheck
+----
+
+.Result
+[role="queryresult",options="header,footer",cols="1* 18
RETURN n.name AS name, n.age AS age
----
+// end::expressions_predicates_type_predicate_properties[]
[role="queryresult",options="header,footer",cols="2* AS isIntList
----
[role="queryresult",options="header,footer",cols="2* as isMixedList
[role="queryresult",options="header,footer",cols="1* Lists]
+* xref:expressions/predicates/list-operators.adoc[Predicates -> List operators]
+* xref:expressions/list-expressions.adoc[List expressions]
[[example-graph]]
== Example graph
diff --git a/modules/ROOT/pages/functions/mathematical-logarithmic.adoc b/modules/ROOT/pages/functions/mathematical-logarithmic.adoc
index 278a8a2f3..412c69268 100644
--- a/modules/ROOT/pages/functions/mathematical-logarithmic.adoc
+++ b/modules/ROOT/pages/functions/mathematical-logarithmic.adoc
@@ -4,7 +4,7 @@
[[query-functions-logarithmic]]
= Mathematical functions - logarithmic
-Logarithmic mathematical functions operate on numeric expressions only, and will return an error if used on any other values. See also xref::syntax/operators.adoc#query-operators-mathematical[Mathematical operators].
+Logarithmic mathematical functions operate on numeric expressions only, and will return an error if used on any other values. See also xref:expressions/mathematical-operators.adoc[Mathematical operators].
[[functions-e]]
diff --git a/modules/ROOT/pages/functions/mathematical-numeric.adoc b/modules/ROOT/pages/functions/mathematical-numeric.adoc
index fb0ecabe7..3401c5c24 100644
--- a/modules/ROOT/pages/functions/mathematical-numeric.adoc
+++ b/modules/ROOT/pages/functions/mathematical-numeric.adoc
@@ -5,7 +5,7 @@
= Mathematical functions - numeric
Numeric mathematical functions operate on numeric expressions only, and will return an error if used on any other values.
-See also xref::syntax/operators.adoc#query-operators-mathematical[Mathematical operators].
+See also xref:expressions/mathematical-operators.adoc[Mathematical operators].
[[example-graph]]
== Example graph
diff --git a/modules/ROOT/pages/functions/mathematical-trigonometric.adoc b/modules/ROOT/pages/functions/mathematical-trigonometric.adoc
index d98ab2db5..b3cdfd19f 100644
--- a/modules/ROOT/pages/functions/mathematical-trigonometric.adoc
+++ b/modules/ROOT/pages/functions/mathematical-trigonometric.adoc
@@ -4,7 +4,7 @@
[[query-functions-trigonometric]]
= Mathematical functions - trigonometric
-Trigonometric mathematical functions operate on numeric expressions only, and will return an error if used on any other values. See also xref::syntax/operators.adoc#query-operators-mathematical[Mathematical operators].
+Trigonometric mathematical functions operate on numeric expressions only, and will return an error if used on any other values. See also xref:expressions/mathematical-operators.adoc[Mathematical operators].
[[functions-acos]]
== acos()
diff --git a/modules/ROOT/pages/functions/predicate.adoc b/modules/ROOT/pages/functions/predicate.adoc
index cd1eb446b..25c6a714f 100644
--- a/modules/ROOT/pages/functions/predicate.adoc
+++ b/modules/ROOT/pages/functions/predicate.adoc
@@ -196,7 +196,7 @@ RETURN any(i IN emptyList WHERE true) as anyTrue, any(i IN emptyList WHERE false
[NOTE]
====
-To check if a property is not `null` use the xref::syntax/operators.adoc#cypher-comparison[`IS NOT NULL` predicate].
+To check if a property is not `null` use the xref:expressions/predicates/comparison-operators.adoc[`IS NOT NULL` predicate].
====
.+exists()+
@@ -330,7 +330,7 @@ The `name` property of each node that has an empty `STRING` `address` property i
The function `isEmpty()`, like most other Cypher functions, returns `null` if `null` is passed in to the function.
That means that a predicate `isEmpty(n.address)` will filter out all nodes where the `address` property is not set.
Thus, `isEmpty()` is not suited to test for `null`-values.
-xref:syntax/operators.adoc#cypher-comparison[`IS NULL` or `IS NOT NULL`] should be used for that purpose.
+xref:expressions/predicates/comparison-operators.adoc[`IS NULL` or `IS NOT NULL`] should be used for that purpose.
====
diff --git a/modules/ROOT/pages/functions/scalar.adoc b/modules/ROOT/pages/functions/scalar.adoc
index 6ec56dd22..54261bd66 100644
--- a/modules/ROOT/pages/functions/scalar.adoc
+++ b/modules/ROOT/pages/functions/scalar.adoc
@@ -1282,7 +1282,7 @@ With this in mind, the below list contains all supported types (as of Neo4j 5.13
This should be taken into account when relying on the output of the `valueType()` function.
-See the xref::values-and-types/type-predicate.adoc[type predicate expression] for an alternative way of testing type values.
+See the xref::expressions/predicates/type-predicate-expressions.adoc[type predicate expression] for an alternative way of testing type values.
.+valueType()+
diff --git a/modules/ROOT/pages/functions/string.adoc b/modules/ROOT/pages/functions/string.adoc
index fef3a40d7..2e4670020 100644
--- a/modules/ROOT/pages/functions/string.adoc
+++ b/modules/ROOT/pages/functions/string.adoc
@@ -16,7 +16,7 @@ When `toString()` is applied to a temporal value, it returns a `STRING` represen
This `STRING` will therefore be formatted according to the https://en.wikipedia.org/wiki/ISO_8601[ISO 8601] format.
====
-See also xref::syntax/operators.adoc#query-operators-string[String operators].
+See also xref::expressions/string-operators.adoc[String concatenation operators].
[role=label--new-5.20]
[[functions-btrim]]
@@ -270,7 +270,7 @@ RETURN normalize('\u212B') = '\u00C5' AS result
======
-To check if a `STRING` is normalized, use the xref:syntax/operators.adoc#match-string-is-normalized[`IS NORMALIZED`] operator.
+To check if a `STRING` is normalized, use the xref:expressions/predicates/string-operators.adoc#string-normalization-operators[`IS NORMALIZED`] operator.
[[functions-normalize-with-normal-form]]
=== normalize() with specified normal form
diff --git a/modules/ROOT/pages/functions/temporal/duration.adoc b/modules/ROOT/pages/functions/temporal/duration.adoc
index 74503b98f..0612c789e 100644
--- a/modules/ROOT/pages/functions/temporal/duration.adoc
+++ b/modules/ROOT/pages/functions/temporal/duration.adoc
@@ -8,7 +8,7 @@ Duration functions allow for the creation and manipulation of temporal `DURATION
[NOTE]
====
-See also xref::values-and-types/temporal.adoc[Temporal values] and xref::syntax/operators.adoc#query-operators-temporal[Temporal operators].
+See also xref::values-and-types/temporal.adoc[Temporal values] and xref::expressions/temporal-operators.adoc[Temporal operators].
====
[[functions-durations]]
diff --git a/modules/ROOT/pages/functions/temporal/index.adoc b/modules/ROOT/pages/functions/temporal/index.adoc
index 0be8324f2..6a4e90508 100644
--- a/modules/ROOT/pages/functions/temporal/index.adoc
+++ b/modules/ROOT/pages/functions/temporal/index.adoc
@@ -54,7 +54,7 @@ The following functions are included on this page:
[NOTE]
====
-See also xref::values-and-types/temporal.adoc[Temporal (Date/Time) values] and xref::syntax/operators.adoc#query-operators-temporal[Temporal operators].
+See also xref::values-and-types/temporal.adoc[Temporal (Date/Time) values] and xref::expressions/temporal-operators.adoc[Temporal operators].
====
diff --git a/modules/ROOT/pages/genai-integrations.adoc b/modules/ROOT/pages/genai-integrations.adoc
index 4de082e41..0e665299e 100644
--- a/modules/ROOT/pages/genai-integrations.adoc
+++ b/modules/ROOT/pages/genai-integrations.adoc
@@ -171,7 +171,7 @@ CALL db.create.setNodeVectorProperty(moviesList[index], 'embedding', vector) //
----
<1> xref:functions/aggregating.adoc#functions-collect[Collect] all 20 `Movie` nodes into a `LIST`.
-<2> Use a xref:values-and-types/lists.adoc#cypher-list-comprehension[list comprehension] (`[]`) to extract the `title` and `plot` properties of the movies in `moviesList` into a new `LIST`.
+<2> Use a xref:expressions/list-expressions.adoc#list-comprehension[list comprehension] (`[]`) to extract the `title` and `plot` properties of the movies in `moviesList` into a new `LIST`.
<3> `db.create.setNodeVectorProperty` is run for each `vector` returned by `genai.vector.encodeBatch`, and stores that vector as a property named `embedding` on the corresponding node.
====
diff --git a/modules/ROOT/pages/indexes/search-performance-indexes/using-indexes.adoc b/modules/ROOT/pages/indexes/search-performance-indexes/using-indexes.adoc
index 1f7cb1ad8..22a53a3eb 100644
--- a/modules/ROOT/pages/indexes/search-performance-indexes/using-indexes.adoc
+++ b/modules/ROOT/pages/indexes/search-performance-indexes/using-indexes.adoc
@@ -849,7 +849,7 @@ Total database accesses: 186, total allocated memory: 472
This plan shows that the previously created range index on the `name` property is now used to solve the predicate.
-[[text-indexes-type-predicate-expressions]]
+[[text-indexes-type-predicates]]
=== Text indexes and type predicate expressions
Text indexes require that predicates only include `STRING` properties.
@@ -886,7 +886,7 @@ Total database accesses: 186, total allocated memory: 472
[TIP]
While type predicate expressions were introduced in Neo4j 5.9, the `IS {two-colons} STRING NOT NULL` syntax only became an index-compatible predicate in Neo4j 5.15.
-For more information, see the page about xref:values-and-types/type-predicate.adoc[type predicate expressions].
+For more information, see the page about xref:expressions/predicates/type-predicate-expressions.adoc[type predicate expressions].
The xref:functions/string.adoc#functions-tostring[`toString`] function can also be used to convert an expression to `STRING` values, and thereby help the planner to select a text index.
diff --git a/modules/ROOT/pages/patterns/reference.adoc b/modules/ROOT/pages/patterns/reference.adoc
index a930a1c34..b43196b43 100644
--- a/modules/ROOT/pages/patterns/reference.adoc
+++ b/modules/ROOT/pages/patterns/reference.adoc
@@ -344,7 +344,7 @@ is equivalent to the following node pattern with a `WHERE` clause:
(n WHERE n.p = valueExp1 AND n.q = valueExp2)
----
-The value expression can be any expression as listed in the section on xref:queries/expressions.adoc[expressions], except for path patterns (which will throw a syntax error) and regular expressions (which will be treated as string literals).
+The value expression can be any expression as listed in the section on xref:expressions/index.adoc[expressions], except for path patterns (which will throw a syntax error) and regular expressions (which will be treated as string literals).
An empty property key-value expression matches all elements.
Property key-value expressions can be combined with a `WHERE` clause.
@@ -860,7 +860,7 @@ It is equivalent to the syntax for quantified relationships, with the following
* Position and syntax of quantifier.
* Semantics of the asterisk symbol.
-* Type expressions are limited to the xref::syntax/operators.adoc#query-operators-boolean[disjunction operator].
+* Type expressions are limited to the xref:expressions/predicates/boolean-operators.adoc[disjunction operator].
* The xref:clauses/where.adoc[WHERE] clause is not allowed.
[[variable-length-relationships-syntax]]
diff --git a/modules/ROOT/pages/patterns/variable-length-patterns.adoc b/modules/ROOT/pages/patterns/variable-length-patterns.adoc
index 04c401e7f..ca951b118 100644
--- a/modules/ROOT/pages/patterns/variable-length-patterns.adoc
+++ b/modules/ROOT/pages/patterns/variable-length-patterns.adoc
@@ -77,7 +77,7 @@ Translating the motifs into Cypher, and adding predicates to match the origin an
(:Station { name: 'Clapham Junction' })
----
-To return both solutions in the same query using these fixed-length path patterns, a xref:clauses/union.adoc[UNION] of two `MATCH` statements would be needed.
+To return both solutions in the same query using these fixed-length path patterns, a xref:queries/combined-queries.adoc[UNION] of two `MATCH` statements would be needed.
For example, the following query returns the `departure` of the two services:
.Query
diff --git a/modules/ROOT/pages/planning-and-tuning/operators/operators-detail.adoc b/modules/ROOT/pages/planning-and-tuning/operators/operators-detail.adoc
index ed700739d..2d5c6202f 100644
--- a/modules/ROOT/pages/planning-and-tuning/operators/operators-detail.adoc
+++ b/modules/ROOT/pages/planning-and-tuning/operators/operators-detail.adoc
@@ -4562,7 +4562,7 @@ Total database accesses: 256, total allocated memory: 7376
== Union operators
Union operators in Cypher combine the results from multiple query parts by merging their rows.
-For more information, see the page about the xref:clauses/union.adoc[`UNION`] clause.
+For more information, see the page about the xref:queries/combined-queries.adoc[`UNION`] clause.
[[query-plan-union]]
diff --git a/modules/ROOT/pages/queries/basic.adoc b/modules/ROOT/pages/queries/basic.adoc
index cb6d57af4..a92f5616e 100644
--- a/modules/ROOT/pages/queries/basic.adoc
+++ b/modules/ROOT/pages/queries/basic.adoc
@@ -743,7 +743,7 @@ There are several ways in which Cypher can be used to search a graph for paths b
To search for patterns of a fixed length, specify the distance (hops) between the nodes in the pattern by using a xref::patterns/reference.adoc#quantifiers[quantifier] (`\{n}`).
For example, the following query matches all `Person` nodes exactly 2 hops away from `Tom Hanks` and returns the first five rows.
-The xref:syntax/operators.adoc#syntax-using-the-distinct-operator[DISTINCT] operator ensures that the result contain no duplicate values.
+The ``DISTINCT` operator ensures that the result contain no duplicate values.
.Query
[source, cypher]
diff --git a/modules/ROOT/pages/clauses/union.adoc b/modules/ROOT/pages/queries/combined-queries.adoc
similarity index 92%
rename from modules/ROOT/pages/clauses/union.adoc
rename to modules/ROOT/pages/queries/combined-queries.adoc
index 89c9746a8..05e8a2892 100644
--- a/modules/ROOT/pages/clauses/union.adoc
+++ b/modules/ROOT/pages/queries/combined-queries.adoc
@@ -1,7 +1,7 @@
:description: The `UNION` clause is used to combine the result of multiple queries.
[[query-union]]
-= UNION
+= Combined queries (`UNION`)
`UNION` combines the results of two or more queries into a single result set that includes all the rows that belong to any queries in the union.
@@ -45,7 +45,7 @@ CREATE (johnny:Actor {name: 'Johnny Depp'}),
Combining the results from two queries is done using `UNION ALL`.
.Query
-// tag::clauses_union_all[]
+// tag::combined_queries_union_all[]
[source, cypher]
----
MATCH (n:Actor)
@@ -54,7 +54,7 @@ UNION ALL
MATCH (n:Movie)
RETURN n.title AS name
----
-// end::clauses_union_all[]
+// end::combined_queries_union_all[]
The combined result is returned, including duplicates.
@@ -76,7 +76,7 @@ The combined result is returned, including duplicates.
By not including `ALL` in the `UNION`, duplicates are removed from the combined result set.
.Query
-// tag::clauses_union[]
+// tag::combined_queries_union[]
[source, cypher]
----
MATCH (n:Actor)
@@ -85,7 +85,7 @@ UNION
MATCH (n:Movie)
RETURN n.title AS name
----
-// end::clauses_union[]
+// end::combined_queries_union[]
The combined result is returned, without duplicates.
@@ -141,6 +141,7 @@ If you are using an older version of Neo4j, use `CALL { ... }` instead.
For more information, see xref:subqueries/call-subquery.adoc#import-variables[CALL subqueries -> Importing variables].
.Query
+// tag::combined_queries_post_union_processing[]
[source, cypher]
----
CALL () {
@@ -153,6 +154,7 @@ UNION ALL
RETURN name, count(*) AS count
ORDER BY count
----
+// end::combined_queries_post_union_processing[]
.Result
[role="queryresult",options="header,footer",cols="2* Post-union processing].
\ No newline at end of file
+For more information, see xref:subqueries/call-subquery.adoc#call-post-union[`CALL` subqueries -> Post-union processing].
diff --git a/modules/ROOT/pages/queries/concepts.adoc b/modules/ROOT/pages/queries/concepts.adoc
index f0caa0fd8..d46e01358 100644
--- a/modules/ROOT/pages/queries/concepts.adoc
+++ b/modules/ROOT/pages/queries/concepts.adoc
@@ -68,7 +68,7 @@ RETURN DISTINCT friend.name AS olderConnections
----
This example uses a xref:patterns/variable-length-patterns.adoc#quantified-relationships[quantified relationship] to find all paths up to `5` hops away, traversing only relationships of type `KNOWS` from the start node `Anna` to other older `Person` nodes (as defined by the xref:clauses/where.adoc[] clause).
-The xref:syntax/operators.adoc#syntax-using-the-distinct-operator[DISTINCT] operator is used to ensure that the `RETURN` clause only returns unique nodes.
+The `DISTINCT` operator is used to ensure that the `RETURN` clause only returns unique nodes.
Paths can also be assigned variables.
For example, the below query binds a whole path pattern, which matches the xref:patterns/shortest-paths.adoc[`SHORTEST`] path from `Anna` to another `Person` node in the graph with a `nationality` property set to `Canadian`.
diff --git a/modules/ROOT/pages/queries/expressions.adoc b/modules/ROOT/pages/queries/expressions.adoc
deleted file mode 100644
index 7f73fb3cb..000000000
--- a/modules/ROOT/pages/queries/expressions.adoc
+++ /dev/null
@@ -1,84 +0,0 @@
-= Cypher expressions
-:description: This page explains which expressions are allowed in Cypher.
-
-This page contains examples of allowed expressions in Cypher.
-
-[[general]]
-== General
-
-* A variable: `n`, `x`, `rel`, `myFancyVariable`, `++`A name with special characters in it[]!`++`.
-* A property: `n.prop`, `x.prop`, `rel.thisProperty`, `++myFancyVariable.`(special property name)`++`.
-* A dynamic property: `n["prop"]`, `rel[n.city + n.zip]`, `map[coll[0]]`.
-* A parameter: `$param`, `$0`.
-* A list of expressions: `['a', 'b']`, `[1, 2, 3]`, `['a', 2, n.property, $param]`, `[]`.
-* A function call: `length(p)`, `nodes(p)`.
-* An aggregate function call: `avg(x.prop)`, `+count(*)+`.
-* A path-pattern: `+(a)-[r]->(b)+`, `+(a)-[r]-(b)+`, `+(a)--(b)+`, `+(a)-->()<--(b)+`.
-* An operator application: `1 + 2`, `3 < 4`.
-* A subquery expression: `COUNT {}`, `COLLECT {}`, `EXISTS {}`, `CALL {}`.
-* A regular expression: `a.name =~ 'Tim.*'`.
-* A `CASE` expression.
-* `null`.
-
-[NOTE]
-====
-Expressions containing unsanitized user input may make your application vulnerable to Cypher injection.
-Consider using xref:syntax/parameters.adoc[parameters] instead.
-Learn more in link:https://neo4j.com/developer/kb/protecting-against-cypher-injection/[Protecting against Cypher Injection].
-====
-
-[NOTE]
-====
-Most expressions in Cypher evaluate to `null` if any of their inner expressions are `null`.
-Notable exceptions are the operators `IS NULL`, `IS NOT NULL`, and the xref:values-and-types/type-predicate.adoc[type predicate expressions].
-====
-
-[[numerical]]
-== Numerical
-
-* A numeric (`INTEGER` or `FLOAT`) literal: `13`, `-40000`, `3.14`.
-* A numeric (`INTEGER` or `FLOAT`) literal in scientific notation: `6.022E23`.
-* A hexadecimal `INTEGER` literal (starting with `0x`): `0x13af`, `0xFC3A9`, `-0x66eff`.
-* An octal `INTEGER` literal (starting with `0o`): `0o1372`, `-0o5671`.
-* A `FLOAT` literal: `Inf`, `Infinity`, `NaN`.
-* `null`.
-
-[NOTE]
-====
-Any numeric literal may contain an underscore `_` between digits.
-There may be an underscore between the `0x` or `0o` and the digits for hexadecimal and octal literals.
-====
-
-[[string]]
-== String
-
-* A `STRING` literal: `'Hello'`, `"World"`.
-* A case-sensitive `STRING` matching expression: `a.surname STARTS WITH 'Sven'`, `a.surname ENDS WITH 'son'` or `a.surname CONTAINS 'son'`.
-* `null`.
-
-[[expressions-string-literals]]
-=== String literal escape sequences
-
-String literals can contain the following escape sequences:
-
-[options="header", cols=">1,<2"]
-|===================
-|Escape sequence|Character
-|`\t`|Tab
-|`\b`|Backspace
-|`\n`|Newline
-|`\r`|Carriage return
-|`\f`|Form feed
-|`\'`|Single quote
-|`\"`|Double quote
-|`\\`|Backslash
-|`\uxxxx`|Unicode UTF-16 code point (4 hex digits must follow the `\u`)
-|===================
-
-[[boolean]]
-== Boolean
-
-* A `BOOLEAN` literal: `true`, `false`.
-* A predicate expression (i.e. an expression returning a `BOOLEAN` value): `a.prop = 'Hello'`, `length(p) > 10`, `a.name IS NOT NULL`.
-* Label and relationship type expressions: `(n:A|B)`, `+()-[r:R1|R2]->()+`.
-* `null`.
diff --git a/modules/ROOT/pages/queries/index.adoc b/modules/ROOT/pages/queries/index.adoc
index b5f941fee..ebd6aee20 100644
--- a/modules/ROOT/pages/queries/index.adoc
+++ b/modules/ROOT/pages/queries/index.adoc
@@ -2,9 +2,9 @@
:description: This page is an overview of the queries section in the Cypher Manual.
This section provides a brief overview of the core concepts of a Cypher query (nodes, relationships, and paths), and examples of how to query a Neo4j graph database.
-It also contains information about Cypher expressions.
+It also discusses how to compose combined queries using `UNION` and conditional queries using `WHEN`.
* xref:queries/concepts.adoc[]
* xref:queries/basic.adoc[]
-* xref:queries/expressions.adoc[]
-* xref:queries/case.adoc[]
+* xref:queries/combined-queries.adoc[]
+
diff --git a/modules/ROOT/pages/subqueries/call-subquery.adoc b/modules/ROOT/pages/subqueries/call-subquery.adoc
index 5f862397c..6b4b3747f 100644
--- a/modules/ROOT/pages/subqueries/call-subquery.adoc
+++ b/modules/ROOT/pages/subqueries/call-subquery.adoc
@@ -494,6 +494,7 @@ Now all `Player` nodes, regardless of whether they have any `PLAYS_FOR` relation
====
+
[[call-execution-order]]
== Execution order of CALL subqueries
@@ -572,7 +573,7 @@ RETURN
[[call-post-union]]
== Post-union processing
-Call subqueries can be used to further process the results of a xref:clauses/union.adoc[] query.
+Call subqueries can be used to further process the results of a xref:queries/combined-queries.adoc[`UNION`] query.
.Using `UNION` within a `CALL` subquery
====
diff --git a/modules/ROOT/pages/subqueries/existential.adoc b/modules/ROOT/pages/subqueries/existential.adoc
index 99a8cca9c..058701595 100644
--- a/modules/ROOT/pages/subqueries/existential.adoc
+++ b/modules/ROOT/pages/subqueries/existential.adoc
@@ -2,7 +2,7 @@
:description: This page describes how to use the EXISTS subquery with Cypher.
An `EXISTS` subquery can be used to find out if a specified pattern exists at least once in the graph.
-It serves the same purpose as a xref::clauses/where.adoc#filter-on-patterns[path pattern] but it is more powerful because it allows you to use `MATCH` and `WHERE` clauses internally.
+It serves the same purpose as a xref::clauses/where.adoc#filter-patterns[path pattern] but it is more powerful because it allows you to use `MATCH` and `WHERE` clauses internally.
[[exists-example]]
== Example graph
@@ -73,7 +73,6 @@ RETURN person.name AS name
1+d|Rows: 1
|===
-
[[existential-nesting]]
== Nesting `EXISTS` subqueries
diff --git a/modules/ROOT/pages/syntax/index.adoc b/modules/ROOT/pages/syntax/index.adoc
index 04a664be0..b4e150bf2 100644
--- a/modules/ROOT/pages/syntax/index.adoc
+++ b/modules/ROOT/pages/syntax/index.adoc
@@ -10,5 +10,4 @@ Further information can be found in the following sections:
* xref::syntax/variables.adoc[Variables]
* xref::syntax/keywords.adoc[Keywords]
* xref::syntax/parameters.adoc[Parameters]
-* xref::syntax/operators.adoc[Operators]
* xref::syntax/comments.adoc[Comments]
diff --git a/modules/ROOT/pages/syntax/operators.adoc b/modules/ROOT/pages/syntax/operators.adoc
deleted file mode 100644
index 1da8140a2..000000000
--- a/modules/ROOT/pages/syntax/operators.adoc
+++ /dev/null
@@ -1,1115 +0,0 @@
-:description: This section contains an overview of operators.
-[[query-operators]]
-= Operators
-
-This page contains an overview of the available Cypher operators.
-
-[[query-operators-summary]]
-== Operators at a glance
-
-
-[subs=none]
-|===
-| xref::syntax/operators.adoc#query-operators-aggregation[Aggregation operators] | `DISTINCT`
-| xref::syntax/operators.adoc#query-operators-property[Property operators] | `.` for static property access, `[]` for dynamic property access, `=` for replacing all properties, `+=` for mutating specific properties
-| xref::syntax/operators.adoc#query-operators-mathematical[Mathematical operators] | `+`, `-`, `*`, `/`, `%`, `^`
-| xref::syntax/operators.adoc#query-operators-comparison[Comparison operators] | `+=+`, `+<>+`, `+<+`, `+>+`, `+<=+`, `+>=+`, `IS NULL`, `IS NOT NULL`
-| xref::syntax/operators.adoc#query-operators-comparison[`STRING`-specific comparison operators] | `STARTS WITH`, `ENDS WITH`, `CONTAINS`, `=~` (regex matching)
-| xref::syntax/operators.adoc#query-operators-boolean[Boolean operators] | `AND`, `OR`, `XOR`, `NOT`
-| xref::syntax/operators.adoc#query-operators-string[String operators] | `+` and `\|\|` (string concatenation), `IS NORMALIZED`
-| xref::syntax/operators.adoc#query-operators-temporal[Temporal operators] | `+` and `-` for operations between durations and temporal instants/durations, `*` and `/` for operations between durations and numbers
-| xref::syntax/operators.adoc#query-operators-map[Map operators] | `.` for static value access by key, `[]` for dynamic value access by key
-| xref::syntax/operators.adoc#query-operators-list[List operators] | `+` and `\|\|` (list concatenation), `IN` to check existence of an element in a list, `[]` for accessing element(s) dynamically
-|===
-
-
-[[query-operators-aggregation]]
-== Aggregation operators
-
-The aggregation operators comprise:
-
-* remove duplicates values: `DISTINCT`
-
-[[syntax-using-the-distinct-operator]]
-=== Using the `DISTINCT` operator
-
-Retrieve the unique eye colors from `Person` nodes.
-
-.Query
-[source, cypher]
-----
-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.
-
-.Result
-[role="queryresult",options="header,footer",cols="1* 6
-RETURN DISTINCT restaurant.name
-----
-
-.Result
-[role="queryresult",options="header,footer",cols="1*+ | +"London"+
-
-3+d|Rows: 1
-|===
-
-See xref::clauses/set.adoc#set-replace-properties-using-map[Replace all properties using a map and `=`] for more details on using the property replacement operator `=`.
-
-
-[[syntax-property-mutation-operator]]
-=== Mutating specific properties of a node or relationship using the `+=` operator
-
-.Query
-[source, cypher]
-----
-CREATE (a:Person {name: 'Sofia', age: 20})
-WITH a
-MATCH (p:Person {name: 'Sofia'})
-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 `Sofia` to `Ellen`, the `age` property is left untouched, and the `livesIn` property is added.
-
-.Result
-[role="queryresult",options="header,footer",cols="3*+`
-* less than: `+<+`
-* greater than: `+>+`
-* less than or equal to: `+<=+`
-* greater than or equal to: `+>=+`
-* `IS NULL`
-* `IS NOT NULL`
-
-
-[[query-operator-comparison-string-specific]]
-=== `STRING`-specific comparison operators comprise:
-
-* `STARTS WITH`: perform case-sensitive prefix searching on `STRING` values.
-* `ENDS WITH`: perform case-sensitive suffix searching on `STRING` values.
-* `CONTAINS`: perform case-sensitive inclusion searching in `STRING` values.
-* `=~`: regular expression for matching a pattern.
-
-[[syntax-comparing-two-numbers]]
-=== Comparing two numbers
-
-.Query
-[source, cypher]
-----
-WITH 4 AS one, 3 AS two
-RETURN one > two AS result
-----
-
-.Result
-[role="queryresult",options="header,footer",cols="1*` 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 evaluates to `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.
-`v IS NOT NULL` is equivalent to `NOT(v IS NULL)`.
-
-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.
-
-
-[[cypher-ordering]]
-=== 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).
-* All comparability tests (`+<+`, `+<=+`, `+>+`, `+>=+`) with `java.lang.Double.NaN` evaluate as false.
-For example, `1 > b` and `1 < b` are both false when b is NaN.
-* String values are compared for ordering using lexicographic order (e.g. `"x" < "xy"`).
-* Boolean values are compared for ordering such that `false < true`.
-* Spatial values cannot be compared using the operators `<`, `+<=+`, `>`, or `>=`.
-To compare spatial values within a specific range, use either the xref:functions/spatial.adoc#functions-withinBBox[`point.withinBBox()`] or the xref:functions/spatial.adoc#functions-point-wgs84-2d[`point()`] function.
-
-* *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 xref::values-and-types/spatial.adoc#cypher-spatial-crs[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:
- ** xref::values-and-types/temporal.adoc#cypher-temporal-instants[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.
- 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.
- ** xref::values-and-types/temporal.adoc#cypher-temporal-durations[_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`.
-* *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 footnote:[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.].
-* Comparing for ordering when one argument is `null` (e.g. `null < 3` is `null`).
-* *Ordering* of values with *different* types:
- ** The ordering is, in ascending order, defined according to the following list:
- *** xref::values-and-types/maps.adoc#cypher-literal-maps[`MAP`]
- *** xref::values-and-types/property-structural-constructed.adoc#structural-types[`NODE`]
- *** xref::values-and-types/property-structural-constructed.adoc#structural-types[`RELATIONSHIP`]
- *** xref::values-and-types/lists.adoc[`LIST`]
- *** xref::patterns/fixed-length-patterns.adoc#path-patterns[`PATH`]
- *** xref::values-and-types/temporal.adoc[`ZONED DATETIME`]
- *** xref::values-and-types/temporal.adoc[`LOCAL DATETIME`]
- *** xref::values-and-types/temporal.adoc[`DATE`]
- *** xref::values-and-types/temporal.adoc[`ZONED TIME`]
- *** xref::values-and-types/temporal.adoc[`LOCAL TIME`]
- *** xref::values-and-types/temporal.adoc[`DURATION`]
- *** xref::queries/expressions.adoc#string[`STRING`]
- *** xref::queries/expressions.adoc#boolean[`BOOLEAN`]
- *** Numbers: xref::queries/expressions.adoc#numerical[`INTEGER`, `FLOAT`]
- ** The value `null` is ordered after all other values.
-* *Ordering* of constructed type values:
- ** For the xref::values-and-types/property-structural-constructed.adoc#constructed-types[constructed types] (e.g. maps and lists), elements of the containers are compared pairwise for ordering and thus determine the ordering of two container types.
-For example, `[1, 'foo', 3]` is ordered before `[1, 2, 'bar']` since `'foo'` is ordered before `2`.
-
-
-[[cypher-operations-chaining]]
-=== 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:
-
-[source, cypher]
-----
-MATCH (n) WHERE 21 < n.age <= 30 RETURN n
-----
-
-is equivalent to
-
-[source, cypher]
-----
-MATCH (n) WHERE 21 < n.age AND n.age <= 30 RETURN n
-----
-
-Thus, it matches all nodes where the age is between 21 and 30.
-
-This syntax extends to all equality `=` and inequality `<>` comparisons, as well as to chains longer than three.
-
-[NOTE]
-====
-Chains of `=` and `<>` are treated in a special way in Cypher.
-
-This means that `1=1=true` is equivalent to `1=1 AND 1=true` and not to `(1=1)=true` or `1=(1=true)`.
-====
-
-For example:
-
-[source, syntax, role=noplay]
-----
-a < b = c <= d <> e
-----
-
-Is equivalent to:
-
-[source, syntax, role=noplay]
-----
-a < b AND b = c AND c <= d AND d <> e
-----
-
-
-[[syntax-using-a-regular-expression-to-filter-words]]
-=== Using a regular expression with `=~` to filter words
-
-.Query
-[source, cypher]
-----
-WITH ['mouse', 'chair', 'door', 'house'] AS wordlist
-UNWIND wordlist AS word
-WITH word
-WHERE word =~ '.*ous.*'
-RETURN word
-----
-
-.Result
-[role="queryresult",options="header,footer",cols="1* 6 AND number < 10)
-RETURN number
-----
-
-.Result
-[role="queryresult",options="header,footer",cols="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.
-
-
-[[syntax-accessing-elements-in-a-list]]
-=== Accessing elements in a list using the `[]` operator
-
-.Query
-[source, cypher]
-----
-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`.
-
-.Result
-[role="queryresult",options="header,footer",cols="1* Protecting against Cypher Injection].
+
+[[boolean]]
+== Boolean
+
+Boolean literals represent `BOOLEAN` values.
+A boolean literal may be written as:
+
+* The literal `true`
+* The literal `false`
+
+[[numerical]]
+== Numerical
+
+Numerical literals can represent `INTEGER` or `FLOAT` values.
+A numerical literal may be written as:
+
+* A decimal `INTEGER` literal: `13`, `-40000`
+* A hexadecimal `INTEGER` literal (prefix `0x`): `0x13af`, `0xFC3A9`, `-0x66eff`
+* An octal `INTEGER` literal (prefix `0o`): `0o1372`, `-0o5671`
+
+//
+
+* A `FLOAT` literal in common notation: `3.14`
+* A `FLOAT` literal in scientific notation: `6.022E23`, `1e-9`
+* Literals for special `FLOAT` values: `Inf`, `Infinity`, `NaN`
+
+[NOTE]
+Any numeric literal may contain an underscore `_` between digits.
+There may be an underscore between the `0x` or `0o` and the digits for hexadecimal and octal literals.
+For example: `1_000_000`, `0x_FC3A9`, and `0o_1372`.
+
+[[string]]
+== String
+
+String literals represent `STRING` values.
+They are written using single(`'`) or double quotes (`"`) and may contain escape sequences using a backslash (`\`).
+A string literal may be written as:
+
+* A `STRING` quoted with single quotes: `'Hello, 42'`
+* A `STRING` quoted with double quotes: `"Hello, 42"`
+* A `STRING` with whitespace: `' hello '`
+* A `STRING` with escape sequences: `'Line 1\nLine 2'`, `'Tab\tseparated'`
+* A `STRING` containing Unicode characters: `'그래프는 어디에나 있다'`
+* A `STRING` using a Unicode code point: `'Name: \u004Aohn'` (produces `'Name: John'`)
+
+[[string-literal-escape-sequences]]
+=== String literal escape sequences
+
+String literals can contain the following escape sequences:
+
+[options="header", cols=">1,<2"]
+|===
+|Escape sequence|Character
+|`\t`|Tab
+|`\b`|Backspace
+|`\n`|Newline
+|`\r`|Carriage return
+|`\f`|Form feed
+|`\'`|Single quote
+|`\"`|Double quote
+|`\\`|Backslash
+|`\uxxxx`|Unicode UTF-16 code point (4 hex digits must follow the `\u`)
+|===
diff --git a/modules/ROOT/pages/values-and-types/index.adoc b/modules/ROOT/pages/values-and-types/index.adoc
index 8f429f49c..3fa6d9649 100644
--- a/modules/ROOT/pages/values-and-types/index.adoc
+++ b/modules/ROOT/pages/values-and-types/index.adoc
@@ -8,10 +8,14 @@ Rather, Cypher will automatically infer the data type of a given value.
More information about the data values and types supported by Cypher can be found in the following sections:
* xref::values-and-types/property-structural-constructed.adoc[]
+* xref:values-and-types/boolean-numeric-string.adoc[]
* xref::values-and-types/temporal.adoc[]
* xref::values-and-types/spatial.adoc[]
-* xref::values-and-types/working-with-null.adoc[]
* xref::values-and-types/lists.adoc[]
* xref::values-and-types/maps.adoc[]
+* xref::values-and-types/working-with-null.adoc[]
* xref::values-and-types/casting-data.adoc[]
-* xref::values-and-types/type-predicate.adoc[]
\ No newline at end of file
+* xref:values-and-types/ordering-equality-comparison.adoc[]
+
+[TIP]
+For information about how to check the type of a value, see xref:expressions/predicates/type-predicate-expressions.adoc[]
diff --git a/modules/ROOT/pages/values-and-types/lists.adoc b/modules/ROOT/pages/values-and-types/lists.adoc
index 0a94f3b38..e24ad30db 100644
--- a/modules/ROOT/pages/values-and-types/lists.adoc
+++ b/modules/ROOT/pages/values-and-types/lists.adoc
@@ -5,14 +5,10 @@ include::https://raw.githubusercontent.com/neo4j-graphacademy/courses/main/ascii
= Lists
Cypher includes comprehensive support for lists.
-This section first describes lists in general, and then discusses how to use list comprehension and pattern comprehension in lists.
[NOTE]
-====
-Information regarding operators, such as list concatenation (`+`), element existence checking (`IN`), and access (`[]`) can be found xref::syntax/operators.adoc#query-operators-list[here].
-The behavior of the `IN` and `[]` operators with respect to `null` is detailed xref::values-and-types/working-with-null.adoc[here].
-====
-
+For information about the list predicate operator `IN`, which checks for list membership, see xref:expressions/predicates/list-operators.adoc[Expressions -> Predicates -> List operators].
+For information list concatenation (`+` and `||`), list element access and slicing (`[]`), as well as list and pattern comprehensions, see xref:expressions/list-expressions.adoc[List expressions].
[[cypher-lists-general]]
== Lists in general
@@ -70,7 +66,7 @@ RETURN list[2]
1+d|Rows: 1
|===
-=== List range and size
+== List range and size
The below examples use the xref::functions/list.adoc#functions-range[`range`] function to create lists.
This function returns a list containing all numbers between given start and end numbers.
@@ -212,169 +208,40 @@ RETURN size(range(0, 10)[0..3]) AS list
|===
-[[cypher-pattern-comprehension]]
-== Pattern comprehension
-
-Pattern comprehension is a syntactic construct available in Cypher for creating a list based on matchings of a pattern.
-A pattern comprehension matches the specified pattern like a normal `MATCH` clause, with predicates like a normal `WHERE` clause, but yields a custom projection as specified.
-
-=== Example graph
-
-The following graph is used for examples below:
-
-image::values_and_types_lists_graph.svg[]
-
-To recreate the graph, run the following query against an empty Neo4j database:
-
-[source, cypher, role=test-setup]
-----
-CREATE
- (keanu:Person {name: 'Keanu Reeves'}),
- (johnnyMnemonic:Movie {title: 'Johnny Mnemonic', released: 1995}),
- (theMatrixRevolutions:Movie {title: 'The Matrix Revolutions', released: 2003}),
- (theMatrixReloaded:Movie {title: 'The Matrix Reloaded', released: 2003}),
- (theReplacements:Movie {title: 'The Replacements', released: 2000}),
- (theMatrix:Movie {title: 'The Matrix', released: 1999}),
- (theDevilsAdvocate:Movie {title: 'The Devils Advocate', released: 1997}),
- (theMatrixResurrections:Movie {title: 'The Matrix Resurrections', released: 2021}),
- (keanu)-[:ACTED_IN]->(johnnyMnemonic),
- (keanu)-[:ACTED_IN]->(theMatrixRevolutions),
- (keanu)-[:ACTED_IN]->(theMatrixReloaded),
- (keanu)-[:ACTED_IN]->(theReplacements),
- (keanu)-[:ACTED_IN]->(theMatrix),
- (keanu)-[:ACTED_IN]->(theDevilsAdvocate),
- (keanu)-[:ACTED_IN]->(theMatrixResurrections)
-----
-
-=== Examples
+== Storing lists as properties
-This example returns a list that contains the year when the movies were released.
-The pattern matching in the pattern comprehension looks for `Matrix` in the movie title and that the node `keanu` (`Person` node with the name `Keanu Reeves`) has a relationship with the movie.
+It is possible to store homogenous lists of simple values as properties.
-.Query
+.Allowed - store homogenous list as a property
[source, cypher]
----
-MATCH (keanu:Person {name: 'Keanu Reeves'})
-RETURN [(keanu)-->(b:Movie) WHERE b.title CONTAINS 'Matrix' | b.released] AS years
+CREATE (n:Label)
+SET n.listProperty = [1, 2, 3]
+RETURN n.listProperty AS homogenousListProperty
----
.Result
[role="queryresult",options="header,footer",cols="1*(b:Movie) | b.title] AS movieTitles
-SET keanu.resume = movieTitles
-RETURN keanu.resume
-----
-
-.Result
-[role="queryresult",options="header,footer",cols="1*(b:Movie) | b.title] + [(keanu)-->(b:Movie) | b.released] AS movieTitles
-SET keanu.resume = movieTitles
-RETURN keanu.resume
+CREATE (n:Label)
+SET n.listProperty = [1, "hello", .45, date()]
+RETURN n.listProperty AS heterogenousListProperty
----
+.Error
[source,error]
----
Neo4j only supports a subset of Cypher types for storage as singleton or array properties. Please refer to section cypher/syntax/values of the manual for more details.
----
-
-
-[[cypher-list-comprehension]]
-== List comprehension
-
-List comprehension is a syntactic construct available in Cypher for creating a list based on existing lists.
-
-For example, the following query returns a new list from the previously created `resume` property (a list of strings) of `Keanu Reeves`:
-
-.Query
-[source, cypher]
-----
-MATCH (keanu:Person {name:'Keanu Reeves'})
-RETURN [x IN keanu.resume WHERE x contains 'The Matrix'] AS matrixList
-----
-
-.Result
-[role="queryresult",options="header,footer",cols="1* Map operators]. +
+For information about how the `[]` operator behaves with respect to `null`, see xref::values-and-types/working-with-null.adoc#cypher-null-bracket-operator[Working with `null` -> The `[\]` operator and `null`].
====
@@ -36,137 +35,3 @@ RETURN {key: 'Value', listKey: [{inner: 'Map1'}, {inner: 'Map2'}]} AS map
|===
-[[cypher-map-projection]]
-== Map projection
-
-Cypher supports map projections, which allows for the construction of map projections from nodes, relationships, and other map values.
-
-A map projection begins with the variable bound to the graph entity to be projected from, and contains a body of comma-separated map elements, enclosed by `{` and `}`.
-
-.Map projection
-[source, syntax]
-----
-map_variable {map_element, [, ...n]}
-----
-
-A map element projects one or more key-value pairs to the map projection.
-There exist four different types of map projection elements:
-
-* Property selector - Projects the property name as the key, and the value from the `map_variable` as the value for the projection.
-* Literal entry - This is a key-value pair, with the value being an arbitrary expression `key: `.
-* Variable selector - Projects a variable, with the variable name as the key, and the value the variable is pointing to as the value of the projection.
-Its syntax is just the variable.
-* All-properties selector - projects all key-value pairs from the `map_variable` value.
-
-The following conditions apply:
-
-* If the `map_variable` points to a `null` value, the whole map projection will evaluate to `null`.
-* The key names in a map must be of type `STRING`.
-
-
-[[cypher-map-projection-examples]]
-=== Example graph
-
-The following graph is used for the examples below:
-
-image::values_and_types_maps_graph.svg[]
-
-To recreate the graph, run the following query against an empty Neo4j database:
-
-[source, cypher, role=test-setup]
-----
-CREATE
- (keanu:Person {name: 'Keanu Reeves', nationality: 'Canadian'}),
- (carrieAnne:Person {name: 'Carrie-Anne Moss'}),
- (theMatrixRevolutions:Movie {title: 'The Matrix Revolutions', released: 2003}),
- (theMatrixReloaded:Movie {title: 'The Matrix Reloaded', released: 2003}),
- (theMatrix:Movie {title: 'The Matrix', released: 1999}),
- (theDevilsAdvocate:Movie {title: 'The Devils Advocate', released: 1997}),
- (theMatrixResurrections:Movie {title: 'The Matrix Resurrections', released: 2021}),
- (keanu)-[:ACTED_IN]->(theMatrix),
- (keanu)-[:ACTED_IN]->(theMatrixRevolutions),
- (keanu)-[:ACTED_IN]->(theMatrixReloaded),
- (keanu)-[:ACTED_IN]->(theMatrixResurrections),
- (keanu)-[:ACTED_IN]->(theDevilsAdvocate),
- (carrieAnne)-[:ACTED_IN]->(theMatrix),
- (carrieAnne)-[:ACTED_IN]->(theMatrixRevolutions),
- (carrieAnne)-[:ACTED_IN]->(theMatrixReloaded),
- (carrieAnne)-[:ACTED_IN]->(theMatrixResurrections)
-----
-
-=== Examples
-
-The below query finds the `Keanu Reeves` node and the movies he has acted in.
-It is an example of a map projection with a literal entry, which in turn also uses map projection inside the aggregating xref:functions/aggregating.adoc#functions-collect[collect()] function.
-
-.Query
-[source, cypher, indent=0]
-----
-MATCH (keanu:Person {name: 'Keanu Reeves'})-[:ACTED_IN]->(movie:Movie)
-WITH keanu, collect(movie{.title, .released}) AS movies
-RETURN keanu{.name, movies: movies}
-----
-
-.Result
-[role="queryresult",options="header,footer",cols="1*(movie:Movie)
-WITH actor, count(movie) AS numberOfMovies
-RETURN actor{.name, numberOfMovies}
-----
-
-.Result
-[role="queryresult",options="header,footer",cols="1*`) operators] allows for comparing the equality of different values.
+
+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:
+
+* `PATH` values are treated as lists of alternating nodes and relationships and are equal to all lists that contain an identical sequence of nodes and relationships.
+* Testing any value against `NULL` with either the `=` or `<>` operator always evaluates to `NULL`.
+This includes `NULL = NULL` and `NULL <> NULL`.
+To reliably test if a value is `NULL` use `v IS NULL` or `v IS NOT NULL` (the latter is equivalent to `NOT(v IS NULL)`).
+
+Other combinations of value types cannot be compared with each other.
+For example, nodes, relationships, and literal maps cannot be compared to one another.
+Comparing incomparable values will throw an error.
+
+[[ordering-and-comparison]]
+== Ordering and comparison of values
+
+xref:clauses/order-by.adoc[`ORDER BY`] requires that all values are orderable.
+The following points explain how comparisons are made when using the `\<=`, `<`,`>=`, `>` operators.
+
+* Numerical values are compared for ordering using numerical order (e.g. `3 < 4` is `TRUE`).
+* All comparability tests with `java.lang.Double.NaN` evaluate as `FALSE`.
+For example, `1 > b` and `1 < b` are both `FALSE` when `b` is NaN.
+* String values are compared for ordering using lexicographic order (e.g. `"x" < "xy"`).
+* Boolean values are compared for ordering such that `FALSE < TRUE`.
+* When comparing values for ordering, if one of the arguments is `NULL`, the result is always `NULL`.
+* xref:values-and-types/spatial.adoc[Spatial values] cannot be compared using the operators `\<=`, `<`,`>=`, `>`.
+To compare spatial values within a specific range, use either the xref:functions/spatial.adoc#functions-withinBBox[`point.withinBBox()`] or the xref:functions/spatial.adoc#functions-point-wgs84-2d[`point()`] function.
+
+[[value-hierarchy]]
+=== Hierarchy of values
+
+Values of different types are ordered based on a predefined hierarchy, from least to greatest, as outlined in the following list:
+
+* xref::values-and-types/maps.adoc#cypher-literal-maps[`MAP`]
+* xref::values-and-types/property-structural-constructed.adoc#structural-types[`NODE`]
+* xref::values-and-types/property-structural-constructed.adoc#structural-types[`RELATIONSHIP`]
+* xref::values-and-types/lists.adoc[`LIST`]
+* xref::patterns/fixed-length-patterns.adoc#path-patterns[`PATH`]
+* xref::values-and-types/temporal.adoc[`ZONED DATETIME`]
+* xref::values-and-types/temporal.adoc[`LOCAL DATETIME`]
+* xref::values-and-types/temporal.adoc[`DATE`]
+* xref::values-and-types/temporal.adoc[`ZONED TIME`]
+* xref::values-and-types/temporal.adoc[`LOCAL TIME`]
+* xref::values-and-types/temporal.adoc[`DURATION`]
+* xref::values-and-types/spatial.adoc[`POINT`]
+* xref::values-and-types/property-structural-constructed.adoc[`STRING`]
+* xref::values-and-types/property-structural-constructed.adoc[`BOOLEAN`]
+* Numbers: xref:values-and-types/property-structural-constructed.adoc[`INTEGER`, `FLOAT`]
+
+[NOTE]
+`NULL` is ordered after all other values.
+
+.Sorting rules for mixed Cypher types
+[source, cypher]
+----
+WITH [42, "hello", NULL, true, {name: "Alice"}, [1, 2, 3], date("2024-02-10")] AS v
+UNWIND v AS values
+RETURN values
+ORDER BY values
+----
+
+.Result
+[role="queryresult",options="header,footer",cols="1* Constructed types].
+
+[[ordering-spatial-temporal]]
+=== Ordering spatial and temporal values
+
+The following applies to the ordering of xref:values-and-types/spatial.adoc[spatial types]:
+
+* `POINT` values are ordered after lists and before temporal types.
+* `POINT` values of different coordinate reference systems (CRS) are ordered by the CRS code (the value of SRID field).
+For the currently supported set of xref::values-and-types/spatial.adoc#cypher-spatial-crs[CRS], the following ascending order applies: `4326`, `4979`, `7302`, `9157`.
+* `POINT` values with the same CRS are ordered by each coordinate value in turn; first `x`, then `y`, and finally `z`.
+* Note that this ordering is different to the order returned by the spatial index, which follows the space filling curve.
+
+The following applies to the ordering of xref:values-and-types/temporal.adoc[temporal types]:
+
+* Temporal types are ordered after spatial types but before strings.
+* Temporal values follow a chronological order.
+For example, `2023-01-01` comes before `2024-01-01`.
+* Temporal values are first sorted by type, then by value.
+For example, `DATETIME` is considered "greater" than a `DATE` and `2023-02-10T12:00:00` comes before `2023-02-10T15:00:00` because it is chronologically earlier.
+* Since there is no perfect way to compare duration values (because months and years have varying lengths), Cypher defines a specific rule for sorting them in `ORDER BY`:
+** 1 year is treated as 365.2425 days (to account for leap years).
+** 1 month is treated as 30.436875 days (which is 1/12 of a year).
+** 1 day is always 24 hours.
+
+The following applies to the comparison of temporal types:
+
+* xref::values-and-types/temporal.adoc#cypher-temporal-instants[Temporal instant values] (like `DATETIME` and `DATE`) can be compared if they are of the same type.
+An earlier instant is considered smaller (less than) compared to a later instant.
+* Instants at the same point in time but with different time zones are not considered equal.
+To ensure consistent ordering, Cypher sorts them first by their actual point in time.
+If two instants have the same time but different time zones, they are ordered by their UTC offset (west to east, meaning negative offsets come first).
+If they have the same time and offset but different named time zones, they are sorted alphabetically by the time zone name.
+* Duration values cannot be directly compared.
+Since the length of a day, month, or year varies, Cypher does not define a strict ordering for durations.
+As a result, comparing two durations `(e.g, duration1 < duration2)` will always return `NULL`.
diff --git a/modules/ROOT/pages/values-and-types/property-structural-constructed.adoc b/modules/ROOT/pages/values-and-types/property-structural-constructed.adoc
index 6b4e1657b..d3c0c75c5 100644
--- a/modules/ROOT/pages/values-and-types/property-structural-constructed.adoc
+++ b/modules/ROOT/pages/values-and-types/property-structural-constructed.adoc
@@ -18,7 +18,7 @@ Property types are the most primitive types in Cypher and include the following:
* Property types can be returned from Cypher queries.
* Property types can be used as xref::syntax/parameters.adoc[parameters].
* Property types can be stored as properties.
-* Property types can be constructed with xref::queries/expressions.adoc[Cypher literals].
+* Property types can be constructed with Cypher literals.
Homogeneous lists of simple types can be stored as properties, although lists in general (see xref::values-and-types/property-structural-constructed.adoc#constructed-types[Constructed types]) cannot be stored as properties.
Lists stored as properties cannot contain `null` values.
@@ -36,7 +36,7 @@ The following data types are included in the structural types category: `NODE`,
* Structural types can be returned from Cypher queries.
* Structural types cannot be used as xref::syntax/parameters.adoc[parameters].
* Structural types cannot be stored as properties.
-* Structural types cannot be constructed with xref::queries/expressions.adoc[Cypher literals].
+* Structural types cannot be constructed with Cypher literals.
The `NODE` data type includes: id, label(s), and a map of properties.
Note that labels are not values, but a form of pattern syntax.
@@ -60,7 +60,7 @@ The following data types are included in the constructed types category: `LIST`
* Constructed types can be returned from Cypher queries.
* Constructed types can be used as xref::syntax/parameters.adoc[parameters].
* Constructed types cannot be stored as properties (with the exception of homogenous lists).
-* Constructed types can be constructed with xref::queries/expressions.adoc[Cypher literals].
+* Constructed types can be constructed with Cypher literals.
The `LIST` data type can be either a homogenous collection of simple values, or a heterogeneous, ordered collection of values, each of which can have any property, structural or constructed type.
@@ -74,7 +74,7 @@ For more details, see xref::values-and-types/working-with-null.adoc[working with
The table below shows the types and their syntactic synonyms.
-These types (and their synonyms) can be used in xref::values-and-types/type-predicate.adoc[type predicate expressions] and in xref::constraints/managing-constraints.adoc#create-property-type-constraints[property type constraints].
+These types (and their synonyms) can be used in xref::expressions/predicates/type-predicate-expressions.adoc[type predicate expressions] and in xref::constraints/managing-constraints.adoc#create-property-type-constraints[property type constraints].
They are also returned as a `STRING` value when using the xref::functions/scalar.adoc#functions-valueType[valueType()] function.
However, not all types can be used in all places.
@@ -121,7 +121,7 @@ The type `PROPERTY VALUE` is expanded to a closed dynamic union of all valid pro
For example, given the closed dynamic type `BOOL | LIST | BOOLEAN | LIST`, the normalized type would be: `BOOLEAN | LIST`.
-This normalization is run on types used in xref::values-and-types/type-predicate.adoc[type predicate expressions], and in xref::constraints/managing-constraints.adoc#create-property-type-constraints[property type constraints].
+This normalization is run on types used in xref::expressions/predicates/type-predicate-expressions.adoc[type predicate expressions], and in xref::constraints/managing-constraints.adoc#create-property-type-constraints[property type constraints].
Type normalization is also used to ensure the consistency of the output for the xref::functions/scalar.adoc#functions-valueType[valueType()] function.
[[ordering-of-types]]
diff --git a/modules/ROOT/pages/values-and-types/spatial.adoc b/modules/ROOT/pages/values-and-types/spatial.adoc
index dce319fb1..0d3f59c2a 100644
--- a/modules/ROOT/pages/values-and-types/spatial.adoc
+++ b/modules/ROOT/pages/values-and-types/spatial.adoc
@@ -13,7 +13,7 @@ Finally, it briefly explains comparability and orderability with regard to spati
====
For more information about spatial functions, allowing for the creation and manipulation of spatial values, see the section on xref::functions/spatial.adoc[Spatial functions].
-For more information about the comparison and ordering of spatial values, see the section on the xref::syntax/operators.adoc#cypher-ordering[ordering and comparison of values].
+For more information about the comparison and ordering of spatial values, see the section on xref::values-and-types/ordering-equality-comparison.adoc#ordering-spatial-temporal[Ordering spatial and temporal values].
====
[[spatial-values-point-type]]
@@ -40,7 +40,7 @@ Four Coordinate Reference Systems (CRS) are supported, each of which falls withi
Data within different coordinate systems are entirely incomparable, and cannot be implicitly converted from one to the other.
This is true even if they are both Cartesian or both geographic but of a different dimension.
For example, if you search for 3D points using a 2D range, you will get no results.
-However, they can be ordered, as discussed in more detail in the section about xref::syntax/operators.adoc#cypher-ordering[ordering and comparison of values].
+However, they can be ordered, as discussed in more detail in the section about xref:values-and-types/ordering-equality-comparison.adoc#ordering-spatial-temporal[Ordering spatial and temporal values].
[[spatial-values-crs-geographic]]
diff --git a/modules/ROOT/pages/values-and-types/temporal.adoc b/modules/ROOT/pages/values-and-types/temporal.adoc
index 106107711..67254ca2e 100644
--- a/modules/ROOT/pages/values-and-types/temporal.adoc
+++ b/modules/ROOT/pages/values-and-types/temporal.adoc
@@ -10,8 +10,8 @@ This section will discuss how Cypher handles time zones, before exploring tempor
[NOTE]
====
* Refer to xref::functions/temporal/index.adoc[Temporal functions - instant types] for information regarding temporal _functions_ allowing for the creation and manipulation of temporal values.
-* Refer to xref::syntax/operators.adoc#query-operators-temporal[Temporal operators] for information regarding temporal _operators_.
-* Refer to xref::syntax/operators.adoc#cypher-ordering[Ordering and comparison of values] for information regarding the comparison and ordering of temporal values.
+* Refer to xref::expressions/temporal-operators.adoc[Temporal operators] for information regarding temporal _operators_.
+* Refer to xref::values-and-types/ordering-equality-comparison.adoc[Equality, ordering, and comparison of value types] for information regarding the comparison and ordering of temporal values.
====
== Temporal value types
diff --git a/modules/ROOT/pages/values-and-types/working-with-null.adoc b/modules/ROOT/pages/values-and-types/working-with-null.adoc
index 7c96a40fa..5d732bd46 100644
--- a/modules/ROOT/pages/values-and-types/working-with-null.adoc
+++ b/modules/ROOT/pages/values-and-types/working-with-null.adoc
@@ -5,7 +5,7 @@
In Cypher, `null` is used to represent missing or undefined values.
All data types in Cypher are nullable.
-This means that xref::values-and-types/type-predicate.adoc#type-predicate-null[type predicate expressions] always return `true` for `null` values.
+This means that xref::expressions/predicates/type-predicate-expressions.adoc#type-predicate-null[type predicate expressions] always return `true` for `null` values.
Conceptually, `null` means **a missing or unknown value**, and it is treated somewhat differently from other values.
For example, returning a property from a node that does not have said property produces `null`.
@@ -20,7 +20,7 @@ This means that the expression `null` = `null` yields `null`, and not `true`.
[[cypher-null-logical-operators]]
== Logical operations with `null`
-The xref::syntax/operators.adoc#query-operators-boolean[logical operators] (`AND`, `OR`, `XOR`, `NOT`) treat `null` as the **unknown value** of three-valued logic.
+The xref::expressions/predicates/boolean-operators.adoc[boolean operators] (`AND`, `OR`, `XOR`, `NOT`) treat `null` as the **unknown value** of three-valued logic.
.Truth table for logical operators
[options="header", cols="^,^,^,^,^,^"]
@@ -41,7 +41,7 @@ The xref::syntax/operators.adoc#query-operators-boolean[logical operators] (`AND
[[cypher-null-in-operator]]
== The `IN` operator and `null`
-The xref::syntax/operators.adoc#syntax-using-in-to-check-if-a-number-is-in-a-list[IN operator] follows similar logic.
+The xref:expressions/predicates/list-operators[`IN` operator] follows similar logic.
If Cypher can ascertain that something exists in a list, the result will be `true`.
Any list that contains a `null` and does not have a matching element will return `null`.
Otherwise, the result will be `false`.
@@ -98,5 +98,5 @@ a[coalesce($lower,0)..coalesce($upper,size(a))]
[[is-null-is-not-null]]
== Using `IS NULL` and `IS NOT NULL`
Testing any value against `null`, either with the `=` operator or with the `<>` operator, always evaluates to `null`.
-Therefore, use the special equality operators xref:syntax/operators.adoc#cypher-comparison[IS NULL or IS NOT NULL].
+Therefore, use the special equality operators xref:expressions/predicates/comparison-operators.adoc[`IS NULL` or `IS NOT NULL`].