UNWIND
Generic Description
Expands a list into one row per element.
Simple example:
UNWIND [1,2,3] AS n RETURN n
Consumer-Level Explanation
Use UNWIND when the query must expands a list into one row per element and the planner needs to see that operation as part of the Cypher row pipeline. Keep the clause explicit because it controls row grain, variable scope, and what later clauses are allowed to reference.
More Detailed Explanation
UNWIND is one of the bridges between document/list-style data and graph-style querying. It turns an in-memory list or collected set into row form so that normal graph or analytic operations can continue. It is essential for bulk parameter ingestion and semi-structured payload normalization.
What this clause is really for:
- it defines one concrete stage in the Cypher row pipeline, so variables available before and after
UNWINDmust be clear - it should make graph structure, temporal filters, document payload shaping, or procedure output explicit instead of relying on client-side interpretation
- planner tooling depends on this clause boundary to know row grain, variable scope, and whether later expressions are reads, writes, schema operations, or projections
Advanced Example
This example keeps UNWIND inside a complete query pipeline so the clause boundary, visible variables, and returned row shape are clear to planner tooling.
MATCH (u:User)-[e:VIEWED]->(d:Document)
TIME e.ts BETWEEN datetime('2025-01-01T00:00:00Z') AND datetime('2025-02-01T00:00:00Z')
WITH u, e, d,
date_trunc('day', e.ts) AS day_bucket,
properties(d) AS doc_map,
unpivot(properties(d.metadata)) AS metadata_rows,
cosine_similarity(vector(properties(d).embedding), vector([0.22, 0.18, 0.44])) AS score
RETURN u.user_id, d.title, day_bucket, keys(doc_map) AS doc_keys, metadata_rows, score
ORDER BY score DESC
LIMIT 15
Real Use Cases
- bulk create/update flows from array parameters
- turning nested metadata arrays into row pipelines
- post-aggregation expansion after collect or comprehension
Real Limitations And Tradeoffs
- large lists create large row sets immediately
- list order can matter if later logic assumes stable sequencing
- it can hide data-volume issues if used on wide collected payloads