Neo4j how to delete nodes recursively from some st

2019-02-26 08:00发布

In my Neo4j database I have a following entities:

@NodeEntity
public class Product {

    private final static String CONTAINS = "CONTAINS";
    private final static String DEFINED_BY = "DEFINED_BY";
    private final static String VOTED_FOR = "VOTED_FOR";
    private final static String PARENT = "PARENT";
    private final static String CREATED_BY = "CREATED_BY";

    @GraphId
    private Long id;

    @RelatedTo(type = PARENT, direction = Direction.INCOMING)
    private Product parent;

    @RelatedTo(type = CONTAINS, direction = Direction.OUTGOING)
    private Set<Product> childProducts = new HashSet<>();

    @RelatedTo(type = DEFINED_BY, direction = Direction.INCOMING)
    private Set<Criterion> criterias = new HashSet<>();

    @RelatedTo(type = VOTED_FOR, direction = Direction.INCOMING)
    private Set<Vote> votes = new HashSet<>();

    @RelatedTo(type = CREATED_BY, direction = Direction.OUTGOING)
    private User user;

}    

@NodeEntity
public class Criterion {

    private final static String CREATED_BY = "CREATED_BY";
    private final static String DEFINED_BY = "DEFINED_BY";

    @GraphId
    private Long id;

    @RelatedTo(type = DEFINED_BY, direction = Direction.OUTGOING)
    private Product owner;

    @RelatedTo(type = CREATED_BY, direction = Direction.OUTGOING)
    private User user;

}

@NodeEntity
public class Vote {

    private static final String VOTED_ON = "VOTED_ON";
    private final static String VOTED_FOR = "VOTED_FOR";
    private static final String CREATED_BY = "CREATED_BY";

    @GraphId
    private Long id;

    @RelatedTo(type = VOTED_FOR, direction = Direction.OUTGOING)
    private Product product;

    @RelatedTo(type = VOTED_ON, direction = Direction.OUTGOING)
    private Criterion criterion;

    @RelatedTo(type = CREATED_BY, direction = Direction.OUTGOING)
    private User user;

}

Product is a composite entity and can contain child Products. Starting from some Product node in the hierarchy I need to delete all Votes on this Product and then I need to recursively delete all child Products, Criteria defined by these nodes and Votes. User nodes must not be deleted.

I have tried this Cypher query:

MATCH (p:Product)-[r:CONTAINS*]-(e) WHERE id(p) = {productId} FOREACH (rel IN r| DELETE rel) DELETE e 

but it deletes only Products and doesn't delete Votes on the start node and all child Criteria and Votes. Please help me with a correct Cypher query. Thanks.

1条回答
叼着烟拽天下
2楼-- · 2019-02-26 08:43

I'd split that up into two queries. The first one recursively collects the the product hierarchy downwards and the second one deletes one product node and its direct environment.

Getting the product hierarchy is simple:

MATCH (p:Product)-[:CONTAINS*]->(childProduct)
WHERE id(p) = {productId}
RETURN id(childProduct) as id

To delete one product we need to delete all relationships of that product node. Additionally all related nodes need to be deleted as well if they are neither user (you want to keep them) or products (think of parent products - they should be kept as well). Also we need to be sure the target nodes are not connected, thats's why the 2nd optional match:

MATCH (p:Product) 
OPTIONAL MATCH (p)-[r]-(t)
WHERE id(p) = {productId}
DELETE r,p
WITH t
OPTIONAL MATCH (t)-[r2:VOTE_ON|:CREATED_BY]->()
WHERE none(x in labels(t) WHERE x in ["User", "Product"])
DELETE t,r2

I did not test this query myself since you didn't provide a test graph. So take this as an idea and modify it until it works.

update

In a chat we found that this cypher statement solves the problem, note that Product has been replaced by Decision label in the model:

MATCH (p:Decision) 
WHERE p.name = "NoSQL" 
WITH p 
OPTIONAL MATCH (p)-[r]-(t) 
DELETE p,r 
WITH t,r 
OPTIONAL MATCH (t)-[r2:VOTED_ON|:CREATED_BY|:VOTED_FOR]-() 
WITH t, r2,r 
WHERE none(x in labels(t) WHERE x in ["User", "Decision"]) 
DELETE t,r2
查看更多
登录 后发表回答