Skip to content

SynapCores / Recipe

Org Chart: Find everyone under a VP

Traverse a 4-level reporting hierarchy with variable-length paths to list every direct and indirect report

All recipes· graph· 5 minutesbeginnercypher
Instance: localhost:8080

Opens your running SynapCores (Org Chart: Find everyone under a VP will be staged for a preview — nothing runs until you click Run). No instance yet? Install free in ~30s.

Share

Objective

Answer "who reports to VP Diana — directly or transitively, however deep the tree?" Recursive CTEs in SQL solve this but require careful base-case and termination logic. In Cypher, a single variable-length pattern walks the whole subtree of an org chart in one line.

Step 1: Create the graph

// Build a 4-level org: CEO -> VPs -> Directors -> Managers -> ICs
MERGE (ceo:Employee {name: "Adrian Cole", title: "CEO"})

MERGE (diana:Employee {name: "Diana Foster", title: "VP Engineering"})
MERGE (marcus:Employee {name: "Marcus Liu", title: "VP Sales"})

MERGE (priya:Employee {name: "Priya Shah", title: "Director Platform"})
MERGE (omar:Employee {name: "Omar Hassan", title: "Director Mobile"})
MERGE (chen:Employee {name: "Chen Wei", title: "Director Field Sales"})

MERGE (jane:Employee {name: "Jane Kim", title: "Engineering Manager"})
MERGE (theo:Employee {name: "Theo Ng", title: "Engineering Manager"})
MERGE (rosa:Employee {name: "Rosa Diaz", title: "Sales Manager"})

MERGE (eng1:Employee {name: "Liam Brown", title: "Senior Engineer"})
MERGE (eng2:Employee {name: "Ava Singh", title: "Engineer"})
MERGE (eng3:Employee {name: "Ben Ortiz", title: "Engineer"})
MERGE (rep1:Employee {name: "Nina Park", title: "Account Executive"})

MERGE (diana)-[:REPORTS_TO]->(ceo)
MERGE (marcus)-[:REPORTS_TO]->(ceo)
MERGE (priya)-[:REPORTS_TO]->(diana)
MERGE (omar)-[:REPORTS_TO]->(diana)
MERGE (chen)-[:REPORTS_TO]->(marcus)
MERGE (jane)-[:REPORTS_TO]->(priya)
MERGE (theo)-[:REPORTS_TO]->(omar)
MERGE (rosa)-[:REPORTS_TO]->(chen)
MERGE (eng1)-[:REPORTS_TO]->(jane)
MERGE (eng2)-[:REPORTS_TO]->(jane)
MERGE (eng3)-[:REPORTS_TO]->(theo)
MERGE (rep1)-[:REPORTS_TO]->(rosa);

Step 2: List everyone in Diana's organisation

// Variable-length path: 1..5 hops up the REPORTS_TO chain back to Diana.
MATCH (report:Employee)-[:REPORTS_TO*1..5]->(vp:Employee {name: "Diana Foster"})
RETURN report.name AS employee, report.title AS title
ORDER BY title, employee;

What's happening

  • [:REPORTS_TO*1..5] matches paths of length 1 to 5 — direct and indirect reports in one query.
  • The query returns 6 people across 3 levels without writing any recursion or UNION ALL.
  • SQL recursive CTEs need a WITH RECURSIVE block, anchor query, and join — typically 15+ lines.
  • Cypher computes this via index-free adjacency: each node holds pointers to its neighbours, so graph traversal is O(matched edges), not O(table size).
  • Swap the VP name to instantly re-run for any subtree — the same pattern works at any scale.

Try this next

MATCH (vp:Employee {name: "Diana Foster"})<-[:REPORTS_TO*]-(report)
RETURN count(report) AS org_size;
MATCH path = (ic:Employee)-[:REPORTS_TO*]->(ceo:Employee {title: "CEO"})
WHERE NOT (ic)<-[:REPORTS_TO]-()
RETURN ic.name AS ic, length(path) AS depth_to_ceo;
MATCH (mgr:Employee)<-[:REPORTS_TO]-(direct)
RETURN mgr.name AS manager, count(direct) AS span_of_control
ORDER BY span_of_control DESC;

Tags

graphcypherhierarchybeginner