Has there been any update to the syntax of an IF/ELSE
statement in Cypher?
I know about CASE
and the FOREACH
"hacks" but they are so unsightly to read :)
I was wanting to do something with optional parameters such as:
CASE WHEN exists($refs.client) THEN MATCH (cl:client {uuid: $refs.client}) END
...
// and later use it like
CASE WHEN exists(cl) THEN DELETE tcr MERGE (t)-[:references]->(cl) END
// and again in my return
RETURN {
client: CASE WHEN exists(cl) THEN {uuid: cl.uuid} ELSE NULL END,
}
I know that doesn't make a lot of sense given the context, but I'm basically passing in a refs object which may or may not contain parameters (or the parameters exist and are NULL)
Somewhere I read there might be an update to how an "if/else" may be handled in neo4j so I really just wanted to check in and see if anyone was aware of a "nicer" way to handle cases like this.
Currently, I just handle all my queries in code and run a bunch of smaller queries, but it requires duplicate lookups for creating and deleting references. I'd like to move it all into one larger query so I can use variable references.
Again, I know I could use FOREACH...CASE
, but when there is a lot of smaller cases like this, it gets hairy.
Currently the error is
{ Error: Invalid input 'S': expected 'l/L' (line 7, column 9 (offset: 246))
" CASE true WHEN exists($refs.client) THEN MATCH (cl:client {uuid: $refs.client}) END"
^
I also know that I can use WITH...CASE
if I'm passing back a known value, but cannot do a MATCH
inside it.
One of the reasons for wanting to do MATCH
inside the CASE
at the top of the query, is because I want the query to fail if the property on refs exists but the MATCH
does not succeed. Using OPTIONAL MATCH
does not accomplish this.
EDIT
Oh, also... I'm reviewing using
MATCH (cl:client {uuid: $refs.client}) WHERE exists($refs.client)
but I recall that not working correctly.
EDIT
I can do MATCH...WHERE exists()
but later it's futile if I can't do MERGE WHERE exists()
EDIT For reference to show why I'm asking about an IF/ELSE, here is the query I'm looking at. I've modified it from the above example so it doesn't error out.
MATCH (u:user {uuid: $uid})-[:allowed_to {read: true}]->(c:company {uuid: $cid})
MATCH (t:timesheet {uuid: $tid})<-[:owns]-(:timesheets)<-[:owns]-(u)
// Make sure the incoming references are valid or fail query
// Here, I'd like only do a match IF $refs.client exists and IS NOT NULL. If it is null or does not exist, I don't want the query to fail. OPTIONAL MATCH will not fail if the value is passed in is invalid but will simply return NULL. Which is why IF/ELSE (or CASE) would be helpful here.
MATCH (cl:client {uuid: $refs.client})
MATCH (ca:case {uuid: $refs.case})
MATCH (s:step {uuid: $refs.step})
MATCH (n:note {uuid: $refs.note})
// clone timesheet entry to a revision
CREATE (t)-[:assembled_with]->(r:revision)
SET r = t, r.created_at = $data.updated_at
WITH *
// Get the old references
MATCH (t)-[tcr:references]->(rc:client)
MATCH (t)-[tcar:references]->(rca:case)
MATCH (t)-[tsr:references]->(rs:step)
MATCH (t)-[tnr:references]->(rn:note)
// Copy old references to revision (won't create new relationships with NULL)
MERGE (r)-[:references]->(rc)
MERGE (r)-[:references]->(rca)
MERGE (r)-[:references]->(rs)
MERGE (r)-[:references]->(rn)
// Update the current timesheet with new data
SET t += $data
// If new references are incoming, delete the old ones and update for new ones
DELETE tcr
DELETE tcar
DELETE tsr
DELETE tnr
MERGE (t)-[:references]->(cl)
MERGE (t)-[:references]->(ca)
MERGE (t)-[:references]->(s)
MERGE (t)-[:references]->(n)
WITH *
// Get the new count of revisions
MATCH (t)-[:assembled_with]->(_r:revision)
RETURN {
uuid: t.uuid,
start: t.start,
end: t.end,
description: t.description,
client: CASE WHEN exists(cl.uuid) THEN {uuid: cl.uuid} ELSE NULL END,
case: CASE WHEN exists(ca.uuid) THEN {uuid: ca.uuid} ELSE NULL END,
step: CASE WHEN exists(s.uuid) THEN {uuid: s.uuid} ELSE NULL END,
note: CASE WHEN exists(n.uuid) THEN {uuid: n.uuid} ELSE NULL END,
revisions: count(_r)
}
Older question, but there are some new tricks to achieve conditional Cypher execution, especially with subqueries introduced in Neo4j 4.1.x.
This knowledge base article covers the options available, and we'll keep the article updated as additional approaches become available.
https://neo4j.com/developer/kb/conditional-cypher-execution/
Note that the APOC approach in my older answer is still valid, and included in the article.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With