Open ADTC opened 8 years ago
Hello @ADTC, and thanks for reaching out to us.
What is the actual query you are having issues with? If you're using OPTIONAL MATCH
, and aren't liking that it is nulling out variables when they aren't found, then perhaps you should try just using MATCH
instead?
Oh darn, I didn't save the query. But yes, in retrospect what you say makes sense. Although, what about a case where I MATCH
some nodes and only OPTIONAL MATCH
some relationships and nodes, and then I want to perform some operation on the MATCH
ed nodes, and another operation on the OPTIONAL MATCH
ed nodes, how can I ignore the nulls without writing conditionals? I guess the easy way out is to split into two separate queries and get rid of OPTIONAL
.
I can't remember exactly what I was doing. If I get it again I'll ping you.
You could filter out the nulls by using collect()
and UNWIND
, but it gets a bit messy. But without the actual query and use case it's difficult to give accurate advice.
I'll close this as resolved then. Feel free to reopen should your memory clear up in the future.
All the best Mats
@Mats-SX I can't reopen the issue. Looks like GitHub issues don't support reopening, or maybe it's a project setting.
I still can't remember my own query, but here is an example from someone else: https://neo4j-users.slack.com/archives/help-cypher/p1464903073001252
MATCH (i:Item {itemID:'79f3a27e-ed18-439c-a1c3-a44f9a6ceacb'})
WITH i
OPTIONAL MATCH (i)-[cz:CURRENT_ZONE]->(z:Zone)
CREATE (i)-[prevZone:PREVIOUS_ZONE {DTS: cz.DTS, friendlyDTS: cz.friendlyDTS}]->(z)
return i;
Above query doesn't work when z
is null. The alternative is:
MATCH (i:Item {itemID:'79f3a27e-ed18-439c-a1c3-a44f9a6ceacb'})
OPTIONAL MATCH (i)-[cz:CURRENT_ZONE]->(z:Zone)
WITH i,z WHERE NOT z IS NULL
CREATE (i)-[prevZone:PREVIOUS_ZONE {DTS: cz.DTS, friendlyDTS: cz.friendlyDTS}]->(z)
return i;
But I thought it's less verbose and cleaner to say:
MATCH (i:Item {itemID:'79f3a27e-ed18-439c-a1c3-a44f9a6ceacb'})
OPTIONAL MATCH (i)-[cz:CURRENT_ZONE]->(z:Zone)
OPTIONAL CREATE (i)-[prevZone:PREVIOUS_ZONE {DTS: cz.DTS, friendlyDTS: cz.friendlyDTS}]->(z)
return i;
@ADTC So when there is no z
node found, you would like to not have the relationship created?
MATCH (i:Item {itemID: '79f3a27e-ed18-439c-a1c3-a44f9a6ceacb'})
MATCH (i)-[cz:CURRENT_ZONE]->(z:Zone)
CREATE (i)-[prevZone:PREVIOUS_ZONE {DTS: cz.DTS, friendlyDTS: cz.friendlyDTS}]->(z)
RETURN i
or even shorter:
MATCH (i:Item {itemID: '79f3a27e-ed18-439c-a1c3-a44f9a6ceacb'})-[cz:CURRENT_ZONE]->(z:Zone)
CREATE (i)-[prevZone:PREVIOUS_ZONE {DTS: cz.DTS, friendlyDTS: cz.friendlyDTS}]->(z)
RETURN i
This query will do that, but it will not return the i
s that do not have the relationship, and perhaps you still want that? Your second query does not do this either, however.
Yes, the choice of returning all i
s including those that do not have the relationship, and that I only optionally create relationships when end nodes z
exist, not when they are null, and I get all i
regardless.
I understand. You could do that like this:
MATCH (i:Item {itemID:'79f3a27e-ed18-439c-a1c3-a44f9a6ceacb'})
MATCH (j:Item {itemID:'79f3a27e-ed18-439c-a1c3-a44f9a6ceacb'})-[cz:CURRENT_ZONE]->(z:Zone)
CREATE (j)-[prevZone:PREVIOUS_ZONE {DTS: cz.DTS, friendlyDTS: cz.friendlyDTS}]->(z)
RETURN i
but it isn't very pretty (and may suffer from performance if there are many i
s and j
s).
I can see why you would want OPTIONAL CREATE
. Will keep this issue open for the language group to consider.
I also would like to see this feature added as currently many single cyphers that were working on 2.3 have to be broken up into multiple cyphers on neo4j 3.
Also the proposed
MATCH (i:Item {itemID:'79f3a27e-ed18-439c-a1c3-a44f9a6ceacb'})
MATCH (j:Item {itemID:'79f3a27e-ed18-439c-a1c3-a44f9a6ceacb'})-[cz:CURRENT_ZONE]->(z:Zone)
CREATE (j)-[prevZone:PREVIOUS_ZONE {DTS: cz.DTS, friendlyDTS: cz.friendlyDTS}]->(z)
RETURN i
Wont work when there are no matches for the pattern (j:Item {itemID:'79f3a27e-ed18-439c-a1c3-a44f9a6ceacb'})-[cz:CURRENT_ZONE]->(z:Zone)
If that pattern matches nothing you won't get i returned.
+1 to optional merge
You can create an optional merge with subqueries, with union each subquery return a result.
call {
return 1 union
with * where 1=2
return 1
}
call {
with * where 1=1
return 2
}
Here is a more complex example:
merge(var_1:Person {id:$model.person.id})
set var_1.name = coalesce($model.person.name, var_1.name)
with *
call {
return 1 union
with var_1
with * where 1=1 and exists($model.person.lead.person.id)
merge(var_2:Person {id:$model.person.lead.person.id})
set var_2.name = $model.person.lead.person.name
merge(var_1)-[lead:LEAD]->(var_2)
return 1
}
call {
return 2 union
with var_1
with * where 1=1 and exists($model.person.hasPosition.position.name)
merge(var_3:Position {name:$model.person.hasPosition.position.name})
merge(var_1)-[hasPosition:HAS_POSITION]->(var_3)
return 2
}
return 'done'
Here are some sample models:
{"person":{"id":"3","name":"Kay","hasPosition":{"position":{"name":"Cloud Architect"}},"lead":{"person":{"id":"1"}}}}
but it's also possible that not all values exist, for example the lead not exist
{"person":{"id":"1","name":"Bernd","lead":{"person":{}},"hasPosition":{"position":{"name":"Manager"}}}}
When I used
OPTIONAL MATCH
andMERGE
together, I encountered a problem. The query ran and crashed with an error logged. I was told to check the log, and I found that the variable I was getting from theOPTIONAL MATCH
was null, when aMERGE
was being performed to create a relationship to it.How do I make it create the relationship only when
OPTIONAL MATCH
returns a non-null value (i.e. a node) for it? I thought the simplest syntax (if this has to be implemented) would be to simply addOPTIONAL
in front ofMERGE
orCREATE
. Of course, Neo4j could also just ignore anyMERGE
orCREATE
involving null value and emit a warning for such.