Side effects while combining two statements using Cypher

本秂侑毒 提交于 2019-12-25 05:43:14

问题


I created the following example case:

MERGE (p1:C5{userId:'1234'})
mERGE (p2:C5{userId:'555'})
MERGE (p3:C5{userId:'1234'})
mERGE (p4:C5{userId:'6969'})
MERGE (p1)-[r1:follow]->(p2) 
MERGE (p2)-[t1:follow]->(p1)
MERGE (p3)-[r2:follow]->(p4) 
MERGE (p4)-[t2:follow]->(p3)
SET r1.type='mirror',
t1.type='real',
r2.type='real',
t2.type='mirror'

I am trying to create a statement which delete relationships from a given Node(by userId prop) only by this criteria:

  1. For a given Node the incoming relationship(follow.type)='mirror'
  2. For a given Node the outgoing relationship(follow.type)='real'

You dont need to have both in order to apply. each rules is individual I am just trying to combine it on the same statement.

So I managed to write something but I have side effects. It deletes all relationshions and it doesnt consider the rules I mentioned:

MATCH (n:C5 { userId: '1234' })<-[r]-(),(g:C5{userId:'1234'})-[y]->() 
        WHERE r.type='mirror' or y.type='real'
        DELETE  r,y

if you check this code you'll see all relationships are gone.

I expected to see only the relationship btw node(1234) and node(6969) to be gone coz both outgoing and incoming relationships individually apply my rules.

Now if I split this query into 2 statements that working as expected:

MATCH (n:C5 { userId: '1234' })<-[r]-() 
            WHERE r.type='mirror' 
            DELETE  r


MATCH (g:C5{userId:'1234'})-[y]->() 
            WHERE y.type='real'
            DELETE  y

But I do want to merge it into one. Thank you, ray.

New case after comments:

MERGE (p1:C4{userId:'1234'})
mERGE (p2:C4{userId:'555'})
MERGE (p1)-[r1:follow]->(p2) 
MERGE (p2)-[t1:follow]->(p1) 
SET r1.type='real',
t1.type='mirror'

Execute the following:

match (n:C4{userId:'1234'})-[y]->(g:C4{userId:'555'}),
      (n:C4{userId:'1234'})<-[r]-(g:C4{userId:'555'})
WHERE y.type='real' and r.type='real' 
set y.type='mirror'
with y,r
match (n:C4{userId:'1234'})-[x]->(g:C4{userId:'555'}),
      (n:C4{userId:'1234'})<-[z]-(g:C4{userId:'555'})
WHERE x.type='real' and z.type='mirror' 
delete x,z

I tried to create here 2 conditions. if 1 condition applied I just do set if 2 condition applied I am doing delete

My case now should trigger the second part which does delete. but that part never triggered I get 0 lines affected.


回答1:


The problem here is the "OR" part.

I mean, in your query, you get 2 relationships, and if the type of the first is "mirror" OR the type of the second is "real" you delete both.

So if one of the conditions you specified is met, both relationships are deleted.

That's also why the splited query is working as expected.

I think you are looking for this:

MATCH (n:C5 { userId: '1234' })<-[r]-()
WHERE r.type='mirror' 
WITH r
MATCH (n:C5 { userId: '1234' })-[y]->()
WHERE y.type='real'
DELETE r,y

Since I got an issue with CASE in DELETE part, I made this one, using WITH to pass r to a second match, and then deleting relationships who met requirements.

If I find the solution using CASE, this answer will be edited.




回答2:


I think you are making it more complicated than it needs to be. Here are different examples of how to do it, with some reasoning and console links. (The consoles will RETURN instead DELETE, so you can play around with them.)

One way you can express the single condition is if you first match the relationships without direction, then include the direction in your condition. Something like

// Query 1a
MATCH (n:C5 {userId: '1234'})-[r]-()
WHERE (r.type = 'mirror' AND n<-[r]-()) OR (r.type = 'real' AND n-[r]->())
DELETE  r

or

// Query 1b
WHERE (r.type='mirror' AND ENDNODE(r) = n) OR (r.type = 'real' AND STARTNODE(r) = n)

See console 1.

You could also do it similar to your original, single condition query. Here you could avoid getting confused by the logic of the condition by moving it into the MATCH pattern.

// Query 2
MATCH (n:C5 {userId: '1234'})<-[r {type:'mirror'}]-(), n-[s {type:'real'}]->()
DELETE r, s

For your sample graph it works just fine, see console 2.

Aside: You will want to reuse the identifier for the node (n) to avoid matching the node twice. The same goes for the query that you added in your edit. When you have matched something and bound it to an identifier, use the identifier. For your last query, that would mean doing MATCH (n:C4 {userId:'1234'})-[y]->(g:C4 {userId:'555'}), n<-[r]-g.

This second query (as well as yours and Supiami's) assumes exactly one relationship in the graph for r and one for s.

If there is no s or no r, the pattern will not match at all. In console 3 I have removed the relationship that would be matched as s from the graph and, as you can see, the query does not match anything for r either.

The query at the top of my answer will handle this situation, but you could also handle it by first matching the node and then optionally matching the two relationship patterns.

// Query 3
MATCH (n:C5 {userId: '1234'})
OPTIONAL MATCH n<-[r {type:'mirror'}]-()
OPTIONAL MATCH n-[s {type:'real'}]->()
DELETE r, s

Try this query at console 4.

The reverse is also true: if there are multiple relationships for r or s, the other relationship will be matched several times. In console 5 I have added another :C5 node with a relationship that will be matched by s in the query. As you can see, two different relationships are returned for s, and the same relationship is returned twice for r. This may not be a problem, because DELETE will know how to handle it. But it is important to be aware of how this happens, if you extend this query or write a more complex one. Otherwise you will get unexpected results.

A final note on style: here are some things to think about to improve the clarity of your examples and queries. This would make it easier for you and for others to reason about them.

  • capitalize relationship types
  • use the relationship types that you define in your setup query, or remove them altogether if they are not relevant
  • use meaningful or generic labels (:User or :A, not :C4 and :C5), or remove them if they are not relevant
  • try to avoid using type as a property name on a relationship
  • be consistent about capitalization on your queries (mERGE, match, WHERE)

These are just conventions, but they are really helpful when sharing and reasoning about queries, and for ruling out clutter when trying to locate a mistake.



来源:https://stackoverflow.com/questions/32733623/side-effects-while-combining-two-statements-using-cypher

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!