cancel
Showing results for 
Search instead for 
Did you mean: 

Head's Up! These forums are read-only. All users and content have migrated. Please join us at community.neo4j.com.

Is there on not match statement?

ri8ika
Graph Voyager

I am trying to set different property if query is matched and not matched. But I'm not able to find in the documentation.

Something like this?

MATCH (n:Node)
// blah, blah, blah
ON MATCH SET n.one = 'one'
ON NOT MATCH SET n.two = 'two'

I also tried using CASE but I got error:

MATCH (n:Node)
// blah, blah, blah
WITH
CASE n.foo
WHEN 'foo'
THEN SET n.one = 'one'
ELSE SET n.two = 'two'
END

Neo.ClientError.Statement.SyntaxError: Invalid input 'n': expected whitespace, comment, '{', node labels, MapLiteral, a parameter, a relationship pattern, '(', '.', '[', "=~", IN, STARTS, ENDS, CONTAINS, IS, '^', '*', '/', '%', '+', '-', '=', '~', "<>", "!=", '<', '>', "<=", ">=", AND, XOR, OR, WHEN, ELSE or END (line 15, column 5 (offset: 220))
"SET n.one= 'one'"
^

1 ACCEPTED SOLUTION

CASE can't be used for conditional Cypher execution like you're doing here (you can't have SET clauses within it).

You can use CASE to produce a different expression depending on the evaluation, which would make more sense if you were attempting to set one of two different values to the same property, but in this case you're setting different properties depending on the evaluation.

There are two options available for you. You can either use conditional procs from APOC Procedures:

MATCH (n:Node)
// blah, blah, blah
CALL apoc.do.when(n.foo = 'foo', 
 "SET n.one = 'one'", 
 "SET n.two = 'two'", 
 {n:n}) YIELD value
...

Or you can use a trick using FOREACH, which relies on the fact that the FOREACH contents will execute per element in the list, so we use CASE to emit a single element list (to trigger the updating Cypher) or an empty list (no-op). Be aware you need a separate FOREACH for each condition, including the else case:

MATCH (n:Node)
// blah, blah, blah
FOREACH (ignoreme in CASE WHEN n.foo = 'foo' THEN [1] ELSE [] END |
 SET n.one = 'one')
FOREACH (ignoreme in CASE WHEN n.foo <> 'foo' THEN [1] ELSE [] END |
 SET n.two = 'two')

View solution in original post

6 REPLIES 6

CASE can't be used for conditional Cypher execution like you're doing here (you can't have SET clauses within it).

You can use CASE to produce a different expression depending on the evaluation, which would make more sense if you were attempting to set one of two different values to the same property, but in this case you're setting different properties depending on the evaluation.

There are two options available for you. You can either use conditional procs from APOC Procedures:

MATCH (n:Node)
// blah, blah, blah
CALL apoc.do.when(n.foo = 'foo', 
 "SET n.one = 'one'", 
 "SET n.two = 'two'", 
 {n:n}) YIELD value
...

Or you can use a trick using FOREACH, which relies on the fact that the FOREACH contents will execute per element in the list, so we use CASE to emit a single element list (to trigger the updating Cypher) or an empty list (no-op). Be aware you need a separate FOREACH for each condition, including the else case:

MATCH (n:Node)
// blah, blah, blah
FOREACH (ignoreme in CASE WHEN n.foo = 'foo' THEN [1] ELSE [] END |
 SET n.one = 'one')
FOREACH (ignoreme in CASE WHEN n.foo <> 'foo' THEN [1] ELSE [] END |
 SET n.two = 'two')

Thanks. I will try with FOREACH. But most of the time I get answer with APOC. This is what I am not using. Can you please guide when I must use this plugin?

APOC is a library of procedures and functions, a kind of swiss-army-knife/wishlist of features we want (and in some cases need) that aren't in the main product but that we can create with custom user procedures and functions.

There is so much in there I can't articulate all of its functionality along with what's convenient vs what's essential (lacking a non-APOC means to accomplish it), but here are a couple notable pieces of functionality that can't yet be replicated with just Cypher:

  1. Batching (when not using CSVs) using apoc.periodic.iterate(). You CAN actually do this in Cypher, but manually, adding LIMIT within your queries, designing them correctly, and executing manually as many times as it takes to process all batches.

  2. JSON handling, both transforming from and to.

  3. Advanced path expansion options. Cypher follows a certain expansion behavior when expanding out, in that a relationship must be unique per path. APOC's path expanders allow different behavior that may be required for specific use cases, usually ones having to do with expanding out to a subgraph efficiently, or finding a distinct count of certain kinds of nodes reachable or within some distance, or when you need to expand out to repeating patterns of node types or relationships.

ri8ika
Graph Voyager

Hi, I'm having little difficulties checking condition. Can we do this just with cypher?

Here's pseudo code to demonstrate my issue:

... match and find value
WITH value
...
if n.foo OR value >= 1
...SET
else
...SET

you can try apoc procedure if else statement for this issue .

given your initial post of

MATCH (n:Node)
// blah, blah, blah
ON MATCH SET n.one = 'one'
ON NOT MATCH SET n.two = 'two'

isnt this what a MERGE would do for you and a MERGE ..... ON MATCH .... ON CREATE https://neo4j.com/docs/cypher-manual/3.5/clauses/merge/#query-merge-on-create-on-match