These examples use the sample graph from the matching page.
NEXT
NEXT runs the query before it, then hands the columns it returns to the query after it, as that query’s incoming rows. Use it to run several steps in one request, or to start a new stage from a smaller set of rows.
MATCH (n:Person)
RETURN n.name AS nm, n.age AS age
NEXT
RETURN nm
ORDER BY nm LIMIT 2
MATCH (n:Person)
RETURN n.city AS city, count(*) AS people
NEXT
RETURN max(people) AS biggestCityPassing nodes on
A returned node is still a node in the next step, so you can match from it:
MATCH (n:Person)
WHERE n.age > 30
RETURN n AS p
NEXT
MATCH (p)-[:KNOWS]->(f)
RETURN p.name, f.nameLonger chains
A chain can have as many steps as you need, and each step is a full query:
MATCH (n:Person)
RETURN n.name AS nm, n.age AS age
NEXT
WITH nm, age
WHERE age > 28
RETURN nm, age
NEXT
RETURN count(*) AS over28After a UNION
A step can be a UNION, and the next step reads the combined rows:
MATCH (p:Person)
RETURN p.name AS name
UNION
MATCH (c:Company)
RETURN c.name AS name
NEXT
RETURN count(*) AS totalA whole chain in braces can also be one side of a UNION:
{ MATCH (p:Person) RETURN p.age AS v NEXT RETURN max(v) AS v }
UNION
{ MATCH (c:Company) RETURN c.founded AS v NEXT RETURN max(v) AS v }Inside subqueries
NEXT works inside CALL, EXISTS and COUNT subqueries, where the chain runs once for each outer row:
MATCH (c:Company)
CALL (c) {
MATCH (p:Person)-[:WORKS_AT]->(c)
RETURN p.age AS age
NEXT
RETURN avg(age) AS avgAge
}
RETURN c.name, avgAge
MATCH (p:Person)
RETURN p.name, COUNT {
MATCH (p)-[:KNOWS]->(f)
RETURN f AS friend
NEXT
MATCH (friend)-[:KNOWS]->(fof)
RETURN fof
} AS friendsOfFriendsWrites
Inside a change, a later step sees what an earlier step wrote:
CREATE (t:Tag {name: 'new'})
RETURN t
NEXT
MATCH (x:Tag)
RETURN count(x) AS tagsRules
- Aliases. Every expression in a
RETURNfollowed byNEXTneeds an alias. Without one:Expression in a RETURN followed by NEXT must be aliased (use AS). - Scope. Only the returned columns carry over.
MATCH (n:Person) RETURN n.name AS nm NEXT RETURN n.agereportsVariable 'n' not found, because the first step did not returnn. NEXTis not yet available inside aCOLLECT { }body.
WHEN
WHEN <condition> THEN <query> runs a query when the condition holds. Add more WHEN ... THEN ... branches and an ELSE <query> as needed: the first branch whose condition holds is the one that runs.
WHEN true THEN RETURN 1 AS x ELSE RETURN 2 AS xConditions on the data
Conditions can be subqueries over the graph:
WHEN EXISTS { MATCH (:Company {name: 'Acme'}) } THEN RETURN 'has Acme' AS result
ELSE RETURN 'no Acme' AS result
WHEN COUNT { MATCH (n:Person) } > 3 THEN RETURN 'big' AS size
ELSE RETURN 'small' AS sizeFor each row, after NEXT
After NEXT, the conditions are checked for each incoming row, and each row takes the first branch that matches:
MATCH (n:Person)
RETURN n.name AS nm, n.age AS age
NEXT
WHEN age > 35 THEN RETURN nm, 'over 35' AS band
WHEN age > 29 THEN RETURN nm, '30 to 35' AS band
ELSE RETURN nm, 'under 30' AS bandFor each row, in a CALL subquery
As the body of a CALL subquery, a conditional runs once per outer row, and a branch can match more data:
MATCH (n:Person)
CALL (n) {
WHEN n.city = 'London' THEN
MATCH (n)-[:WORKS_AT]->(c)
RETURN c.name AS employer
ELSE RETURN 'elsewhere' AS employer
}
RETURN n.name, employerWithout ELSE
When no branch matches and there is no ELSE, the conditional returns no rows, so WHEN false THEN RETURN 1 AS x returns nothing. In a CALL, rows that match no branch are dropped. Use OPTIONAL CALL to keep them with null values:
MATCH (n:Person)
OPTIONAL CALL (n) {
WHEN n.age >= 40 THEN RETURN 'senior' AS band
}
RETURN n.name, bandSeveral steps in a branch
Put a NEXT chain in braces:
WHEN true THEN {
MATCH (n:Person)
RETURN n.city AS city, count(*) AS people
NEXT
RETURN max(people) AS biggest
}
ELSE RETURN 0 AS biggestCombining with UNION
Conditionals in braces combine with UNION. Each one names its columns with AS:
{ WHEN true THEN RETURN 'a' AS x }
UNION
{ WHEN false THEN RETURN 'b' AS x ELSE RETURN 'c' AS x }Writes
Branches can write, inside a change. See Conditional writes:
MATCH (n:Person)
CALL (n) {
WHEN n.age > 30 THEN CREATE (:Senior {name: n.name})
}
RETURN count(*)Rules
- Same columns. All branches return the same column names. Otherwise:
All branches of a conditional query must return the same column names. - Where it goes. A
WHENstarts a query, followsNEXT, forms aCALLbody, or is a braced side of aUNION. To branch on the results of aMATCH, return them and continue afterNEXT, as above. - Not yet available:
UNIONinside a branch, andWHENinside anEXISTS,COUNTorCOLLECTbody.

