Advanced Cypher -1


 Let’s dive into variable-length paths in Neo4j Cypher. 🚀


🔹 What are Variable-Length Paths?

In Cypher, sometimes you don’t know how many hops (relationships) exist between nodes.
Variable-length paths let you specify a range of hops.

Syntax:

()-[:RELTYPE*min..max]->()
  • *1..3 → between 1 and 3 hops

  • * → any length (be careful, can explode results!)

  • *0.. → zero or more hops

  • *1.. → one or more hops


🔹 1. Example: Direct and Indirect Friendships

MATCH (a:User {name: "Alice"})-[:FRIEND*1..3]->(b:User) RETURN b

👉 Finds users reachable from Alice within 1 to 3 friendship hops.

  • 1 hop: direct friends

  • 2 hops: friends of friends

  • 3 hops: friends of friends of friends


🔹 2. Any Path Length

MATCH (a:User {name: "Alice"})-[:FRIEND*]->(b:User) RETURN b

👉 Finds all users connected to Alice, no matter how many hops.
⚠️ Use with caution on large graphs → can return huge results.


🔹 3. Paths with Direction

MATCH (u:User {name: "Alice"})-[:WORKS_ON*1..2]->(p:Project) RETURN p

👉 Alice’s projects within 1 or 2 WORKS_ON hops.


🔹 4. Paths with Both Directions

MATCH path=(u:User {name: "Alice"})-[:FRIEND*1..2]-(b:User) RETURN path

👉 Matches undirected friendships up to 2 hops.


🔹 5. Capturing the Path

You can store the path in a variable:

MATCH path=(a:User {name: "Alice"})-[:FRIEND*1..3]->(b:User) RETURN path, length(path) AS hops

👉 Returns the entire path plus the number of hops.


✅ Summary:

  • *1..3 = between 1 and 3 hops.

  • * = unlimited hops (careful!).

  • Can use directed or undirected arrows.

  • Use length(path) when you need the number of hops.

let’s build this step by step with some example graph data, then run the query and see the expected output.


🔹 Example Graph Data (CREATE statements)

Let’s say we have users and projects:

CREATE (a:User {name: "Alice"}) CREATE (b:User {name: "Bob"}) CREATE (c:User {name: "Charlie"}) CREATE (p1:Project {name: "ProjectX"}) CREATE (p2:Project {name: "ProjectY"}) CREATE (p3:Project {name: "ProjectZ"}) MERGE (a)-[:WORKS_ON]->(p1) MERGE (a)-[:WORKS_ON]->(b) // Alice collaborates with Bob MERGE (b)-[:WORKS_ON]->(p2) // Bob works on ProjectY MERGE (c)-[:WORKS_ON]->(p3) // Charlie works on ProjectZ

🔹 Graph Structure Visually

Alice → ProjectX Alice → Bob → ProjectY Charlie → ProjectZ

🔹 Query

MATCH (u:User {name: "Alice"})-[:WORKS_ON*1..2]->(p:Project) RETURN p.name

🔹 Step-by-Step Explanation

  • *1..2 means:

    • 1 hop (direct): Alice → ProjectX

    • 2 hops: Alice → Bob → ProjectY


🔹 Expected Output

p.name
ProjectX
ProjectY

ProjectZ is NOT included, because Alice isn’t connected to Charlie within 2 WORKS_ON hops.


✅ This shows how variable-length paths allow Alice to reach both direct and indirect projects she’s involved in.

in Cypher, once you match a path, you can use built-in path functions to explore details like how long it is, what nodes are included, and what relationships exist.


🔹 Path Functions in Neo4j

1. length(path)

  • Returns the number of relationships in the path.

Example:

MATCH p = (u:User {name: "Alice"})-[:WORKS_ON*1..3]->(p:Project) RETURN p, length(p) AS path_length

Output (sample):

p (path)path_length
(Alice)-[:WORKS_ON]->(ProjectX)1
(Alice)-[:WORKS_ON]->(Bob)-[:WORKS_ON]->(ProjectY)2

2. nodes(path)

  • Returns a list of all nodes in the path.

Example:

MATCH p = (u:User {name: "Alice"})-[:WORKS_ON*1..2]->(proj:Project) RETURN nodes(p) AS path_nodes

Output:

path_nodes
[Alice, ProjectX]
[Alice, Bob, ProjectY]

3. relationships(path)

  • Returns a list of all relationships in the path.

Example:

MATCH p = (u:User {name: "Alice"})-[:WORKS_ON*1..2]->(proj:Project) RETURN relationships(p) AS path_rels

Output:

path_rels
[(:Alice)-[:WORKS_ON]->(:ProjectX)]
[(:Alice)-[:WORKS_ON]->(:Bob), (:Bob)-[:WORKS_ON]->(:ProjectY)]

✅ So the workflow is:

  • length() → How many hops?

  • nodes() → Who/what is in the path?

  • relationships() → Which connections got us there?


Let’s go step by step with a sample dataset, then I’ll show you how to use length(), nodes(), and relationships() together in queries.


🔹 Sample Graph Setup

Let’s imagine this small graph:

(:User {name: "Alice"}) (:User {name: "Bob"}) (:User {name: "Charlie"}) (:Project {name: "ProjectX"}) (:Project {name: "ProjectY"})

Relationships:

(Alice)-[:WORKS_ON]->(Bob) (Bob)-[:WORKS_ON]->(ProjectX) (Alice)-[:WORKS_ON]->(ProjectY) (Charlie)-[:WORKS_ON]->(ProjectY)

1️⃣ Find Alice’s paths up to 2 hops

MATCH p = (u:User {name: "Alice"})-[:WORKS_ON*1..2]->(proj:Project) RETURN p

Possible results:

  • Path1: (Alice)-[:WORKS_ON]->(ProjectY)

  • Path2: (Alice)-[:WORKS_ON]->(Bob)-[:WORKS_ON]->(ProjectX)


2️⃣ Return path length

MATCH p = (u:User {name: "Alice"})-[:WORKS_ON*1..2]->(proj:Project) RETURN p, length(p) AS path_length

Output:

p (path)path_length
(Alice)-[:WORKS_ON]->(ProjectY)1
(Alice)-[:WORKS_ON]->(Bob)-[:WORKS_ON]->(ProjectX)2

3️⃣ Return nodes along the path

MATCH p = (u:User {name: "Alice"})-[:WORKS_ON*1..2]->(proj:Project) RETURN nodes(p) AS path_nodes

Output:

path_nodes
[Alice, ProjectY]
[Alice, Bob, ProjectX]

4️⃣ Return relationships along the path

MATCH p = (u:User {name: "Alice"})-[:WORKS_ON*1..2]->(proj:Project) RETURN relationships(p) AS path_rels

Output:

path_rels
[(:Alice)-[:WORKS_ON]->(:ProjectY)]
[(:Alice)-[:WORKS_ON]->(:Bob), (:Bob)-[:WORKS_ON]->(:ProjectX)]

5️⃣ All together in one query

MATCH p = (u:User {name: "Alice"})-[:WORKS_ON*1..2]->(proj:Project) RETURN length(p) AS hops, nodes(p) AS path_nodes, relationships(p) AS path_rels

Output:

hopspath_nodespath_rels
1[Alice, ProjectY][(:Alice)-[:WORKS_ON]->(:ProjectY)]
2[Alice, Bob, ProjectX][(:Alice)-[:WORKS_ON]->(:Bob), (:Bob)-[:WORKS_ON]->(:ProjectX)]

👉 This way, you can see the full path, how many steps it took, who’s involved (nodes), and the exact edges (relationships).

Comments