Hands-on Challenges
The Hands-on Challenges domain presents tasks where you write Cypher against a known graph and the result is checked precisely - column names, values, and often row order. The skill being tested is translating a plain-English requirement into a query that returns exactly what was asked, no more.
Read the grading criteria first
Decide what the result columns must be named (use AS aliases), whether duplicates are unwanted (DISTINCT), whether ordering is specified (ORDER BY), and whether rows with no match must still appear (OPTIONAL MATCH with a null check). Extra columns or extra rows fail a strict comparison even when the graph logic is right.
Worked example
"For each movie with more than three actors, return the title and actor count, highest count first."
MATCH (m:Movie)<-[:ACTED_IN]-(a:Person)
WITH m, count(a) AS actors
WHERE actors > 3
RETURN m.title AS title, actors
ORDER BY actors DESC
Reasoning: WITH m, count(a) groups by the movie and aggregates the actors; filtering on the aggregate cannot happen in MATCH WHERE, so WHERE follows the WITH. count(a) rather than count(*) matters when the match can be optional. Ordering by the alias keeps the output deterministic.
Challenges that recur
Creating a constraint or index with IF NOT EXISTS before a merge-heavy update; refactoring a chain of OPTIONAL MATCH clauses into a WITH ... WHERE x IS NULL filter; using UNWIND $list AS item to create many nodes from a parameter; computing shortest paths with shortestPath((a)-[*..15]-(b)) and bounding the depth; and returning collected values with collect(DISTINCT ...).
Traps
Aliasing incorrectly or omitting the alias so the column is named after the expression. Grouping accidentally by including an extra variable in the WITH/RETURN projection, which splits the aggregate into more rows. Using MERGE for a whole pattern and creating duplicate nodes. Relying on implicit row order without ORDER BY. Forgetting that aggregation over zero rows returns one row only when there is no grouping key.