Skip to content

Commit e5dcc86

Browse files
authored
SURF-449 Add documentation for GQL FOR as alternate syntax for UNWIND (#1503)
https://linear.app/neo4j/issue/SURF-449/gql-compliance-for-as-replacement-for-unwind-gq10
1 parent f04f60c commit e5dcc86

7 files changed

Lines changed: 113 additions & 5 deletions

File tree

modules/ROOT/content-nav.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
** xref:clauses/delete.adoc[]
2020
** xref:clauses/filter.adoc[]
2121
** xref:clauses/finish.adoc[]
22+
** xref:clauses/for.adoc[]
2223
** xref:clauses/foreach.adoc[]
2324
** xref:clauses/let.adoc[]
2425
** xref:clauses/limit.adoc[]

modules/ROOT/pages/appendix/gql-conformance/analogous-cypher.adoc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,11 @@ Cypher provides the GQL naming aliases xref:functions/aggregating.adoc#functions
4040
* GQL's `PERCENTILE_DISC()` function is equivalent to Cypher's xref:functions/aggregating.adoc#functions-percentiledisc[`percentileDisc()`] function.
4141
Cypher provides the GQL naming aliases xref:functions/aggregating.adoc#functions-percentile-cont[`percentile_cont()`] and xref:functions/aggregating.adoc#functions-percentile-disc[`percentile_disc()`].
4242

43-
| GQ10, GQ11, GQ23, GQ24
44-
| `FOR` statement: list value support, binding table support, `WITH ORDINALITY`, `WITH OFFSET`
45-
| Unnests a list or a binding table by expanding the current working table.
46-
Cypher uses xref:clauses/unwind.adoc[`UNWIND`] instead.
47-
Unlike the `FOR` statement, `UNWIND` does not support yielding indexes and offsets.
43+
| GQ11, GQ23, GQ24
44+
| `FOR` statement: `WITH ORDINALITY`, `WITH OFFSET`, binding table support
45+
| GQL extends the `FOR` statement with ordinality, offset, and binding table sources.
46+
Cypher does not implement these optional GQL forms.
47+
For list unnesting, as of Neo4j 2026.03, Cypher provides xref:clauses/for.adoc[`FOR variable IN expression`] (feature GQ10) and xref:clauses/unwind.adoc[`UNWIND expression AS variable`], which are equivalent for plain lists but do not support `WITH ORDINALITY`, `WITH OFFSET`, or `FOR` over a binding table reference.
4848

4949
| GV12
5050
| 64-bit signed integer numbers

modules/ROOT/pages/appendix/gql-conformance/supported-optional.adoc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,11 @@ For example, GQL’s graph reference values `CURRENT_GRAPH` and `CURRENT_PROPERT
191191
| xref:clauses/let.adoc[`LET`]
192192
|
193193

194+
| [[gq10]] GQ10
195+
| `FOR` statement: list value support
196+
| xref:clauses/for.adoc[`FOR`]
197+
| As of Neo4j 2026.03, Cypher supports `FOR variable IN expression`, equivalent to xref:clauses/unwind.adoc[`UNWIND expression AS variable`].
198+
194199
| GQ13
195200
| `ORDER BY` and page statement: `LIMIT`
196201
| xref:clauses/limit.adoc[`LIMIT`], xref:clauses/order-by.adoc[`ORDER BY`]
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
:description: `FOR` expands a list into a sequence of rows (GQL-aligned syntax; Neo4j 2026.03).
2+
:table-caption!:
3+
:page-role: new-neo4j-2026.03 cypher-25-only
4+
5+
[[query-for]]
6+
= FOR
7+
8+
The `FOR` clause makes it possible to transform any list back into individual rows. These lists can be parameters that were passed in, previously `collect`-ed result, or other list expressions.
9+
10+
The `FOR` is the GQL conformant synonym of xref:clauses/unwind.adoc[`UNWIND`].
11+
`FOR` is valid wherever `UNWIND` is valid and has the same semantics.
12+
`FOR` and `UNWIND` differ only in syntax.
13+
14+
[source, syntax]
15+
----
16+
FOR variable IN expression
17+
----
18+
For comparison, the Cypher `UNWIND` form is:
19+
20+
[source, syntax]
21+
----
22+
UNWIND expression AS variable
23+
----
24+
25+
[NOTE]
26+
====
27+
Neo4j does not guarantee the row order produced by `FOR`.
28+
The only clause that guarantees a specific row order is xref:clauses/order-by.adoc[].
29+
====
30+
31+
32+
[[for-expanding-a-list]]
33+
== Unwinding a list
34+
35+
We want to transform the literal list into rows named `x` and return them.
36+
37+
.Query
38+
[source, cypher]
39+
----
40+
FOR x IN [1, 2, 3, null]
41+
RETURN x, 'val' AS y
42+
----
43+
44+
Each value of the original list -- including `null` -- is returned as an individual row.
45+
The same outcome is shown here using the equivalent `UNWIND` form:
46+
47+
[source, cypher]
48+
----
49+
UNWIND [1, 2, 3, null] AS x
50+
RETURN x, 'val' AS y
51+
----
52+
53+
.Result
54+
[role="queryresult",options="header,footer",cols="2*<m"]
55+
|===
56+
| x | y
57+
| 1 | "val"
58+
| 2 | "val"
59+
| 3 | "val"
60+
| <null> | "val"
61+
2+|Rows: 4
62+
|===
63+
64+
65+
[[for-equivalence-with-unwind]]
66+
== Further behavior
67+
68+
All cases described for xref:clauses/unwind.adoc[`UNWIND`] apply to `FOR`: empty lists, nested lists, expressions that are not lists, parameters, and combinations with `WITH`, `RETURN`, subqueries, and so on.

modules/ROOT/pages/clauses/index.adoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ m| xref::clauses/return.adoc[RETURN ... [AS]]
5353
m| xref::clauses/unwind.adoc[UNWIND ... [AS]]
5454
| Expands a list into a sequence of rows.
5555

56+
m| xref::clauses/for.adoc[FOR]
57+
| Expands a list into a sequence of rows (GQL-aligned syntax; same semantics as `UNWIND`).
58+
label:cypher[Cypher 25 only] label:new[Introduced in Neo4j 2026.04]
59+
5660
m| xref::clauses/with.adoc[WITH ... [AS]]
5761
| Allows query parts to be chained together, piping the results from one to be used as starting points or criteria in the next.
5862

modules/ROOT/pages/clauses/unwind.adoc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@
66
The `UNWIND` clause makes it possible to transform any list back into individual rows.
77
These lists can be parameters that were passed in, previously `collect`-ed result, or other list expressions.
88

9+
[NOTE]
10+
====
11+
As of Neo4j 2026.04, the same semantics are also available with GQL conformant syntax: xref:clauses/for.adoc[`FOR variable IN expression`].
12+
`UNWIND` remains fully supported; the two forms are equivalent for list unnesting.
13+
====
14+
915
[NOTE]
1016
====
1117
Neo4j does not guarantee the row order produced by `UNWIND`.

modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,30 @@ Cypher 25 was introduced in Neo4j 2025.06 and can only be used on Neo4j 2025.06+
2323
Features removed in Cypher 25 are still available on Neo4j 2025.06+ databases either by prepending a query with `CYPHER 5` or by having Cypher 5 as the default language for the database.
2424
For more information, see xref:queries/select-version.adoc[].
2525

26+
[[cypher-deprecations-additions-removals-2026.04]]
27+
== Neo4j 2026.04
28+
29+
=== New in Cypher 25
30+
31+
[cols="2", options="header"]
32+
|===
33+
| Feature
34+
| Details
35+
36+
a|
37+
label:functionality[]
38+
label:new[]
39+
[source, cypher, role="noheader"]
40+
----
41+
FOR x IN [1, 2, 3]
42+
RETURN x
43+
----
44+
45+
a|
46+
The xref:clauses/for.adoc[`FOR`] clause (optional GQL feature xref:appendix/gql-conformance/supported-optional.adoc#gq10[GQ10]) expands a list into rows using GQL conformant syntax: `FOR variable IN expression`.
47+
48+
|===
49+
2650
[[cypher-deprecations-additions-removals-2026.03]]
2751
== Neo4j 2026.03
2852

0 commit comments

Comments
 (0)