Head's Up! These forums are read-only. All users and content have migrated. Please join us at community.neo4j.com.
09-17-2018 04:30 AM
Hi!
I've got some problems to get the OPTIONAL MATCH to work when using the WITH and WHERE operators.
To simplify my complex query I have created the below example. I would like to return all Cats (a) and all persons (p) for whom all friends are bffs.
The problem is that if there is no such person then I will not get anything in result. I would still like the cat to be returned. I understand why it happens but how do I rewrite the query? Please don't just tell me to swap order of the two queries. 😉 Thanks!
Regards Ivar Hagen (Developer at Volvo Cars, Gothenburg, Sweden).
CREATE (a:Animal {type:'Cat', name:'Garfield'})
CREATE (p1:Person {name:'Abby'})
CREATE (p2:Person {name:'Betty'})
CREATE (p3:Person {name:'Carol'})
CREATE (p1)-[:HAS_FRIEND {type:'bff'}]->(p2)
CREATE (p1)-[:HAS_FRIEND {type:'bff'}]->(p3) // Removing this row and the query will return an empty set []
CREATE (p2)-[:HAS_FRIEND {type:'bff'}]->(p1)
CREATE (p2)-[:HAS_FRIEND]->(p3)
MATCH(a:Animal)
WHERE a.type = "Cat"
WITH COLLECT(a) AS a
OPTIONAL MATCH(p:Person)-[r2:HAS_FRIEND]->(p2:Person)
WITH a, p, COLLECT(p2) AS p2, COUNT(p2) AS friends, SIZE( (p)-[:HAS_FRIEND {type:"bff"}]->(:Person) ) AS bffs
WHERE friends = bffs
WITH a, p, p2
RETURN *
Solved! Go to Solution.
09-18-2018 01:07 AM
Thanks!
The All function is a good solution instead of using COUNT and SIZE, but when there are no persons who has all friends as bffs then it still returns empty. I want it to return the Animals (a) no matter what.
Could the All function be combined with the CASE solution maybe?
This is good enough for me. 🙂
MATCH(a:Animal)
WHERE a.type = "Cat"
WITH COLLECT(a) AS a
OPTIONAL MATCH(p:Person)-[r2:HAS_FRIEND]->(p2:Person)
WITH CASE WHEN all(r in collect(r2) WHERE r.type = 'bff') THEN collect(p2) ELSE [] END AS bffs, a, p
RETURN *
09-17-2018 06:51 AM
I kinda managed to solve it myself by using CASE instead of WHERE. 😉
MATCH(a:Animal)
WHERE a.type = "Cat"
WITH COLLECT(a) AS a
OPTIONAL MATCH(p:Person)-[r2:HAS_FRIEND]->(p2:Person)
WITH a, p,
CASE WHEN (COUNT(p2) - SIZE( (p)-[:HAS_FRIEND {type:"bff"}]->(:Person) ) ) <> 0 THEN NULL ELSE COLLECT(p2) END AS x
WITH distinct a, x
RETURN *
09-17-2018 04:47 PM
You could also do:
MATCH(a:Animal)
WHERE a.type = "Cat"
WITH COLLECT(a) AS a
OPTIONAL MATCH(p:Person)-[r2:HAS_FRIEND]->(p2:Person)
WITH a,p, collect(r2) as rels, collect(p2) as friends
WHERE all(r in rels WHERE r.type = 'bff')
RETURN *
09-18-2018 01:07 AM
Thanks!
The All function is a good solution instead of using COUNT and SIZE, but when there are no persons who has all friends as bffs then it still returns empty. I want it to return the Animals (a) no matter what.
Could the All function be combined with the CASE solution maybe?
This is good enough for me. 🙂
MATCH(a:Animal)
WHERE a.type = "Cat"
WITH COLLECT(a) AS a
OPTIONAL MATCH(p:Person)-[r2:HAS_FRIEND]->(p2:Person)
WITH CASE WHEN all(r in collect(r2) WHERE r.type = 'bff') THEN collect(p2) ELSE [] END AS bffs, a, p
RETURN *
All the sessions of the conference are now available online