2

Here's a simple graph:

(:a)-[:r]->(:b)

If want to to delete (:b), I can do this with:

MATCH (a)-[r]->(b :b)
DELETE a, r, b

However, (b) can have multiple relationships and nodes coming off of it (and those nodes can recursively have more relationships and nodes too). Something like this:

(:a)-[:r]->(:b)-[:s]->(x)-[:r]->(y)- ... ->(z)

How can I recursively delete every node and relationship beyond (b)?

inersha
  • 422
  • 5
  • 20
  • Note that if you omit the colon in Cypher, you specify the _variable_ and not the _label_. Hence, your query does not only delete `(:a)-[:r]->(:b)` subgraphs, but all `(...)-[...]-(:b)` subgraph, where the source node and the edge can have arbitrary labels. Instead, you would want `MATCH (a:a)-[r:r]->(b:b) DELETE a, r, b` – Gabor Szarnyas Nov 19 '16 at 15:18
  • Just to clarify, is there a specific node `b` that you want to delete (as well as its connected subgraph), or do you want to do this for all nodes with the label `:b`? If you only want to delete a specific `b` node and its subgraph, what differentiates this node from others of the `:b` label? Is it a `name` property? Some other property? – InverseFalcon Nov 19 '16 at 16:46
  • @InverseFalcon Yes, there is a specific `:b` node, and it has a property with a unique index value. Sorry about the confusion; I tried to make the example code as simple as possible (but obviously it was a little too simple! ) – inersha Nov 19 '16 at 17:27

2 Answers2

4

DETACH DELETE is going to be useful here. This first deletes all relationships from a node, then deletes the node itself. That makes your query easier, as all you need is a query for all nodes reachable from your b node.

I'm going to assume for the moment that this b node in your question is a specific node, instead of every single node with the label :b. I do encourage you to reread the developer documentation on variables and labels, as I'm guessing there's a little confusion here.

So, assuming a specific b node, and assuming that it has a name property that differentiates it, you might use this query to delete it and the entire subgraph connected to it and reachable from it.

MATCH (b:b)-[*0..]-(x)
WHERE b.name = 'b'
WITH DISTINCT x
DETACH DELETE x

Note that because we don't care about the relationship type, and because we've specified 0 or more relationships, x will match to b and its entire connected subgraph no matter how many relationships away. Detaching and deleting x will delete all relationships in the subgraph and then all nodes in the subgraph.

InverseFalcon
  • 29,576
  • 4
  • 38
  • 51
  • The above query deletes all ancestors as well as descendants even after specifying a direction which is not good at all. I wonder why? – gameFrenzy07 Jun 30 '20 at 17:53
  • That shouldn't be the case, if a direction is added it should only be expanding in the specified direction. If you have a particular graph on which you can recreate this, can you create a separate question then provide the link here? – InverseFalcon Jul 02 '20 at 02:19
1

To delete recursively from a node, you can use path variables: p=(source)-[type*minimumHops..maximumHops]->(target) (by default, minimumHops is 1).

Example dataset:

CREATE
  (a:a)-[:r]->(b:b),
  (b)-[:r]->(c:c),
  (c)-[:r]->(d:d),
  (b)-[:r]->(e:e)

Query:

MATCH (a:a)-[r:r]->(b:b)
OPTIONAL MATCH p=(b)-[:r*]->(c)
DELETE a, r, b, p

An alternative, equivalent query:

MATCH
  (a:a)-[r:r]->(b:b),
  p=(b)-[:r*0..]->(c)
DELETE a, r, p

It's worth noting that both will work in the cornercase where you only have a single (:a)-[:r]->(:b) edge in your graph. The first query does this by specifying the path in an OPTIONAL MATCH, while the second one does it by allowing paths of zero hops.

Gabor Szarnyas
  • 4,410
  • 3
  • 18
  • 42