Change a property with condition - neo4j

The query shall check wether a relation is already existing and in that case should check if a property has a special value and change it depending on the check. If that relation doesn exist it shall be created.
I have tried several ways and what comes closest is
MERGE (u:User {uuid: {userUUID}}) -[r:relation {rType: {rType}}]-> (n:Node)
ON CREATE SET
r.uuid = {relUUID},
r.status = {relStatus}
ON MATCH SET
r.status = {relStatus}
WHERE r.status = "1" // Only if r.status of the existing pattern is 1 it shall be changed to the value of relStatus
RETURN r
The WHERE isnt correct syntax - maybe someone has a hint how I can check a property and only change the property based on a special trigger when using ON MATCH.
Thanks.

This should work:
MERGE (u:User {uuid: {userUUID}}) -[r:relation {rType: {rType}}]-> (n:Node)
ON CREATE SET
r.uuid = {relUUID},
r.status = {relStatus}
ON MATCH SET
r.status = CASE WHEN r.status = "1" THEN {relStatus} ELSE r.status END
RETURN r;

Related

how to create and update nodes and property using plain cypher query?

How do I create and update nodes and property using plain cypher query?
Below is my query:
MERGE (c:contact {guid : '500010'})
ON CREATE SET
c.data_source = '1',
c.guid = '500010',
c.created = timestamp()
ON MATCH SET
c.lastUpdated = timestamp()
MERGE (s:speciality {specialtygroup_desc : 'cold'})
ON CREATE SET s.data_source = '1',
s.specialtygroup_desc = 'fever',
s.created = timestamp()
ON MATCH SET s.data_source = '1',
s.specialtygroup_desc = 'comman cold',
s.lastUpdated = timestamp()
MERGE (c)-[r:is_specialised_in]->(s)
ON CREATE SET
r.duration = 1
ON MATCH SET
r.duration = r.duration + 1
On the first run, node is created as "fever".
On the second run, I have updated the specialty_group to "common cold". But it is creating new node with "fever". I am not able to update the "fever" to "common cold".
What changes should I make to the above query?
The MERGE (s:speciality {specialtygroup_desc : 'cold'}) clause looks for a specialtygroup_desc value of "cold".
During the first execution, that MERGE clause finds no "cold" node -- so it creates one, and the subsequent ON CREATE clause changes it to "fever".
During the second execution, that MERGE again finds no "cold" node (since it is now a "fever" node), so it again creates a "cold" node and the ON CREATE clause yet again changes it to "fever". The ON MATCH clause is never used. This is why you end up with another "fever" node.
Unfortunately, you have not explained your use case in enough detail to offer a recommendation for how to fix your code.
I think you want to update all node "cold" to "common cold" and if not exists "cold" or "common cold", create new "fever" ?
My suggestion:
OPTIONAL MATCH (ss:speciality {specialtygroup_desc : 'cold'}
SET ss.specialtygroup_desc='common cold', ss.lastUpdated = timestamp()
MERGE (c:contact {guid : '500010'})
ON CREATE SET
c.data_source = '1',
c.guid = '500010',
c.created = timestamp()
ON MATCH SET
c.lastUpdated = timestamp()
MERGE (s:speciality {specialtygroup_desc : 'common cold'})
ON CREATE SET s.data_source = '1',
s.specialtygroup_desc = 'fever',
s.created = timestamp()
MERGE (c)-[r:is_specialised_in]->(s)
ON CREATE SET
r.duration = 1
ON MATCH SET
r.duration = r.duration + 1

Neo4j Creating a relationship conditionally based on one of the property of node

I need to create two different type of relationship between two nodes. Type of relationship depends upon one of the property of the node.
For Example,
I have two nodes USER and EVENT. I have two relationships to create between them.
1. invite
2. requestToInvite
Even node has property inviteOnly.
Create a "Invite" relationship if inviteOnly is true. Otherwise create "requestToInvite" relationship.
This is what i am trying:
MATCH (u:User)
WHERE ID(u) = 13
WITH u
MATCH (e:Events)
WHERE ID(e) = 0
WITH u,e
CREATE (u)-[:inviteONLYTrue]->(e) WHERE e.inviteOnly = true
CREATE (u)-[:inviteONLYFALSE]->(e) WHERE e.inviteOnly = false
WITH u,e
RETURN u,e
Currently there is no conditional but you can work around it by iterating over a zero or one-element list which is created by a CASE statement.
MATCH (u:User) WHERE ID(u) = 13
MATCH (e:Events) WHERE ID(e) = 0
FOREACH (_ in case e.inviteOnly when true then [1] else [] end |
CREATE (u)-[:inviteONLYTrue]->(e) )
FOREACH (_ in case e.inviteOnly when false then [1] else [] end |
CREATE (u)-[:inviteONLYFALSE]->(e) )
RETURN u,e
APOC Procedures just updated with support for conditional cypher execution, but in this particular case all you'll need is a way to create a relationship with a dynamic relationship type. APOC has a procedure for this too. Here's an example:
MATCH (u:User)
WHERE ID(u) = 13
WITH u
MATCH (e:Events)
WHERE ID(e) = 0
WITH u,e, CASE WHEN e.inviteOnly THEN 'inviteONLYTrue' ELSE 'inviteONLYFALSE' END as relType
CALL apoc.create.relationship(u, relType, {}, e) YIELD rel
RETURN u,e

Set/Change property with dynamic name using Cypher

So when I try to set up a property name/value pair, I'm not sure what the property name will be. It will depend on a meta data node.
Two metadata nodes:
{ id:1, value:'name' }
{ id:2, value:'age' }
I need to add a property for a Person node but I don't want to use condition statement (and cypher does not have condition statement). I want something like:
if (metadata.id = 1) {
set person.name = 'xx'
} else if (metadata.id = 2) {
set person.age = 'xx'
}
or:
match (m:metadata{id:1}), (p:person{id:1}) set p.'m.value' = 'xx'
I don't want to use the if / else condition statement. Is there a cypher condition statement, or how can this be achieved?
You can use WHERE for filtering on conditions
MATCH (p:Person) WHERE p.age > 21 SET p.drunk = true
or you can use a CASE expression to generate a zero or one-element list that you then can use with FOREACH
MATCH (p:Person)
WITH p, (case when p.age > 21 then [1] else [] end) as drunk_filter
FOREACH (x in drunk_filter | SET p.drunk = true)
Foreach has the advantage that the query continues after that.

Add value to array if its not already in there

I want to add a value to an array if its not already there.
So far my code looks something like this (note that both r.names and {name} are arrays, and [1] + [2] = [1,2]):
MERGE (r:resource {hash:{hash}})
ON CREATE SET r.names = {name}
ON MATCH SET r.names = r.names + {name}
but obviously if {name} is already in r.names, it just gets added again. How can I add {name} only if r.names doesn't already contain it?
I guess you need to use the FOREACH + CASE WHEN trick: using a case when you use either a 1 element array (if your condition is true) or a 0 element array otherwise as iterator used in FOREACH. FOREACH cannot be used in a ON MATCH or ON CREATE handler, so we put it after the MERGE and use a coalesce to cover the case when r.names does not yet exist:
MERGE (r:Resource {hash:{hash}})
FOREACH(x in CASE WHEN {name} in r.names THEN [] ELSE [1] END |
SET r.names = coalesce(r.names,[]) + {name}
)
RETURN r.names
Use FILTER to get an array of the elements that aren't already in r.names and add them:
MERGE (r:resource {hash:{hash}})
ON CREATE SET r.names = {new_names}
ON MATCH SET r.names = r.names + FILTER(
el FOR el in {new_names} IF NOT el IN r.names
)

Neo4j, Cypher: How to update a property name?

I have a set of nodes with a property, myproperty = "James" I want to update that property from (myproperty) to (name).
Is there any way to this with Cypher?
Solved by myself, heres what I did:
MATCH (n:term)
SET n.name = n.label
REMOVE n.label
RETURN n
You can change your old column name by using following query
MATCH (n:term)
SET n.name = n.myproperty
REMOVE n.myproperty
RETURN n
match (a:employee {employeeId:123,location:1})
set a.newProperty=a.oldProperty
remove a.oldProperty
return a;

Resources