ThirstForKnowledge
ThirstForKnowledge

Reputation: 1284

Find all leaves of a selected subgraph with Neo4j/ Cypher

Initial Situation

Graphic representation

CREATE (Root:CustomType {name: 'Root'})
CREATE (NodeA:CustomType {name: 'NodeA'})
CREATE (NodeB:CustomType {name: 'NodeB'})
CREATE (NodeC:CustomType {name: 'NodeC'})
CREATE (NodeD:CustomType {name: 'NodeD'})
CREATE (NodeE:CustomType {name: 'NodeE'})
CREATE (NodeF:CustomType {name: 'NodeF'})
CREATE (NodeG:CustomType {name: 'NodeG'})
CREATE (NodeH:CustomType {name: 'NodeH'})
CREATE (NodeI:CustomType {name: 'NodeI'})
CREATE (NodeJ:CustomType {name: 'NodeJ'})
CREATE (NodeK:CustomType {name: 'NodeK'})
CREATE (NodeL:CustomType {name: 'NodeL'})
CREATE (NodeM:CustomType {name: 'NodeM'})
CREATE (NodeN:CustomType {name: 'NodeN'})
CREATE (NodeO:CustomType {name: 'NodeO'})
CREATE (NodeP:CustomType {name: 'NodeP'})
CREATE (NodeQ:CustomType {name: 'NodeQ'})

CREATE
  (Root)-[:CONTAINS]->(NodeA),
  (Root)-[:CONTAINS]->(NodeB),
  (Root)-[:CONTAINS]->(NodeC),
  (NodeA)-[:CONTAINS]->(NodeD),
  (NodeA)-[:CONTAINS]->(NodeE),
  (NodeA)-[:CONTAINS]->(NodeF),
  (NodeE)-[:CONTAINS]->(NodeG),
  (NodeE)-[:CONTAINS]->(NodeH),
  (NodeF)-[:CONTAINS]->(NodeI),
  (NodeF)-[:CONTAINS]->(NodeJ),
  (NodeF)-[:CONTAINS]->(NodeK),
  (NodeI)-[:CONTAINS]->(NodeL),
  (NodeI)-[:CONTAINS]->(NodeM),
  (NodeJ)-[:CONTAINS]->(NodeN),
  (NodeK)-[:CONTAINS]->(NodeO),
  (NodeK)-[:CONTAINS]->(NodeP),
  (NodeM)-[:CONTAINS]->(NodeQ);

To be solved challenge

.

MATCH
  path = (:CustomType {name:'NodeA'})-[:CONTAINS*]->(:CustomType {name:'NodeJ'}) /* simplified */
WITH
  nodes(path) as selectedPath
  /* here: necessary magic to identify the leaf nodes of the subtree */
RETURN
  leafNode;

Upvotes: 2

Views: 431

Answers (1)

stdob--
stdob--

Reputation: 29172

You correctly noted that the check node with no children is suitable only for the entire tree. So you need to go through all the relationships in the subtree, and find such a node of the subtree that is as the end of the relationship, but not as the start of the relationship:

MATCH
  path = (:CustomType {name:'NodeA'})-[:CONTAINS*]->(:CustomType {name:'NodeJ'})
UNWIND relationShips(path) AS r
WITH collect(DISTINCT endNode(r))   AS endNodes, 
     collect(DISTINCT startNode(r)) AS startNodes
UNWIND endNodes AS leaf
WITH leaf WHERE NOT leaf IN startNodes
RETURN leaf

Upvotes: 1

Related Questions