问题
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