Neo4j Cypher: Create a relation only if the end node exists

霸气de小男生 提交于 2019-12-07 17:26:47

问题


For the following Cypher statement:

start n=node:types(id={typeId}), g=node:groups(id={groupId})
create unique (n)<-[:has_type]-(unit {props})-[:has_group]->(g)
return unit

There are cases when g may be null (i.e. a group with id groupId does not exist). In such a case, what should I do to make this statement still create the unit, but skip the has_group relation to g? Right now, unit does not get created, presumably because g is null.

I'm using Neo4j Advanced 1.8

Thanks!


回答1:


I would suggest to move the definition of g to the where clause, since starting at a non-existing node gives error and thus one can't continue the query to the create phase. Note the '?' which handles the null values in Cypher:

 start n=node:types(id={typeId})
 create unique (n)<-[:has_type]-(unit {props})-[:has_group]->(g)
 where g.id?={groupId}
 return unit

the query might need some tweaking, this is just my first untested shot.

edit: After some trying I came to a conclusion, that you might want to do 2 different queries, first for creating the first part of relationships with the unique node which is always and the second to create the relationship to the group which may not happen:

start n=node:types(id={typeId})
create unique (n)<-[:has_type]-(unit {props})    
return unit

start unit=node:unitProps({unitPropsValue}) ,g=node:groups(id={groupId}) 
create unique unit-[:has_group]->g    
return g

the second query will fail with an error in case the group does not exist, but that does not matter since you will still reach the target. For some strange reason I couldn't manage to implement some restrictions in the where clause like I tried in the first shot. following query seems to simply jump over the where conditions (maybe a bug?) although in my comprehension of Cypher it shall match the already existing group, but it does create a new g node instead:

start n=node(1) 
create unique n-[:TYPE1]-(uniq {uid:333})
with uniq
create unique uniq-[:TYPE2]->g 
where has(g.gid) and g.gid=999 
return g



回答2:


You can use WITH clause to achieve this in one query,

start n=node:types(id={typeId})
create unique (n)<-[:has_type]-(unit {props})
WITH unit
START g=node:groups(id={groupId})
create unique (unit)-[:has_group]->(g)
WHERE g <> null
return unit

if g is null, second won't get executed at all. even WHERE g <> null might not be required here. Kindly try and confirm




回答3:


You can try this

   MATCH (g:groups) 
   WHERE id(g)={groupId}
   create unique (unit {props})-[:has_group]->(g)
   WITH unit, create unique (unit)-[:has_type]->(n)
   return unit



回答4:


Since this is the only thing I can find related to this, I will add how I am dealing with this since none of the other answers are good enough for my purposes.

MATCH (a:TEST{id:1}) 
OPTIONAL MATCH (b:TEST)
WHERE b.id IN [2,3,5]
// collect b so that there are no nulls, and rows aren't lost when no match
WITH a, collect(b) AS c
FOREACH(n IN c | CREATE UNIQUE (a)-[:HAS]->(n))
RETURN a

Will work for Cypher 2.3+ (I can't test any earlier than that)

For those with APOC, you can also use CALL apoc.cypher.doIt() to break out the write.



来源:https://stackoverflow.com/questions/13244894/neo4j-cypher-create-a-relation-only-if-the-end-node-exists

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