== Fetch a Tree with Neo4j Today I came across a really interesting http://stackoverflow.com/questions/30940411/fetch-a-tree-with-neo4j[StackOverflow question]: > Given a forest of trees in a Neo4j REST server, I`m trying to return a single tree given the root vertex. Being each tree quite large, I need a de-duplicated list of all vertices and edges in order to be able to reconstruct the full tree on the client side. //setup [source,cypher] ---- CREATE (r:root) FOREACH (i IN range(1,5)| CREATE (r)-[:PARENT]->(c:child { id:i })); MATCH (c:child) FOREACH (j IN range(1,5)| CREATE (c)-[:PARENT]->(:child { id:c.id*10+j })); ---- //graph How many nodes and rels do we have in the graph ? One root node, 5 children and 25 grandchildren, makes 31 nodes, 30 relationships. [source,cypher] ---- match (n)-[r]-() return count(distinct n) as nodes, count(distinct r) as rels ---- //table === Answer by Brian Underwood http://twitter.com/cheerfulstoic[Brian] http://stackoverflow.com/a/30944366/728812[answered] the question with this suggestion: > if you want to get all of the nodes and relationships in one go, you may need to execute two queries: [source,cypher] ---- MATCH p = (r:root)-[*]->(x) WHERE NOT(x-->()) UNWIND nodes(p) AS Vertex RETURN DISTINCT Vertex; ---- //table [source,cypher] ---- MATCH p = (r:root)-[*]->(x) WHERE NOT(x-->()) UNWIND rels(p) AS Edge RETURN DISTINCT startNode(Edge), endNode(Edge); ---- //table === Update 1: Combine queries I thought about it that it should be easy to combine both queries into one: [source,cypher] ---- MATCH p = (r:root)-[*]->(x) WHERE NOT(x-->()) UNWIND nodes(p) AS Vertex WITH collect(DISTINCT Vertex) as nodes, collect(rels(p)) as paths UNWIND paths AS Edges UNWIND Edges as Edge WITH nodes, collect(distinct Edge) as rels RETURN size(nodes),size(rels),nodes,rels ---- //table === Update 2: Only return ids Speed it up by just ignoring the additional (expensive) where condition and let `distinct` do its job. [source,cypher] ---- MATCH p = (r:root)-[*]->(x) UNWIND nodes(p) AS Vertex WITH collect(DISTINCT id(Vertex)) as nodes, collect(rels(p)) as paths UNWIND paths AS Edges UNWIND Edges as Edge WITH nodes, collect(distinct [id(startNode(Edge)),id(endNode(Edge))]) as rels RETURN size(nodes),size(rels),nodes,rels ---- //table === Update 3: The "Cypher" Way Actually cypher returns one path per match-step, so even the sub-paths that build up the tree are returned, so each `x` is returned once from the match. (Those intermediate ones were filtered out before). So we can just use them and `collect` them in a distinct list. That's for the nodes. For the rels we only need to look at the `last` relationship before `x` as the others were already returned by previous paths. We collect the distinct last rels and extract the id's of the start- and end-nodes to be returned. [source,cypher] ---- MATCH p = (:root)-[r*]->(x) WITH collect(DISTINCT id(x)) as nodes, [r in collect(distinct last(r)) | [id(startNode(r)),id(endNode(r))]] as rels RETURN size(nodes),size(rels), nodes, rels ---- //table === Update 4: Including the root node If you also want to include the root node, just change `*` to `*0..` like here: [source,cypher] ---- MATCH p = (:root)-[r*0..]->(x) WITH collect(DISTINCT id(x)) as nodes, [r in collect(distinct last(r)) | [id(startNode(r)),id(endNode(r))]] as rels RETURN size(nodes),size(rels), nodes, rels ---- //table