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.
Related
I checked on the developer manual that you can filter with property on a variable length with relationship like below cypher.
MATCH p =(charlie:Person)-[* { blocked:false }]-(martin:Person)
WHERE charlie.name = 'Charlie Sheen' AND martin.name = 'Martin Sheen'
RETURN p
What I am looking here is can I filter by some logic on numeric properties on the relationship with a variable length.
For example, change the {blocked:false} in the query to a numeric properties like {amount_paid} and filter by amount_paid > 20.
So I can hop on Person by the relationship with amount_paid > 20.
You can use the predicate ALL:
MATCH p=(charlie:Person {name: 'Charlie Sheen')-[*]-(martin:Person {name: 'Martin Sheen')
WHERE ALL(rel in relationships(p) WHERE rel.amount_paind > 20)
RETURN p
From my searchings I did not find a way to set the property of an object dynamically, only by defining it hardcoded (Like below the "Detail" property)
Here is my sample:
Neo4j Graph or via Neo4j Console
MATCH(p:Person)-[r]->(m:Movie)
WITH { Person: p.name,
Detail: collect(r.roles)
} AS Result
RETURN Result
My target (not working yet):
MATCH(p:Person)-[r]->(m:Movie)
WITH { Person: p.name,
CASTED_FOR: // --> Only values(r.roles) for relationship "CASTED_FOR" needed here
ACTED_IN: // --> Only values(r.roles) for relationship "ACTED_IN" needed here
} AS Result
RETURN Result
I know I could make e.g. [r:CASTED_FOR] or WHERE Type(r) = "CASTED_FOR", but I don't like to have multiple WITH and MATCH queries.
Thank you
This query uses Cypher's list comprehension construct to do what you want:
MATCH (p:Person)-[r]->(:Movie)
WITH p, COLLECT(r) AS rs
RETURN {
Person: p.name,
CASTED_FOR: [x IN rs WHERE TYPE(x) = 'CASTED_FOR' | x.roles],
ACTED_IN: [x IN rs WHERE TYPE(x) = 'ACTED_IN' | x.roles]
} AS Result
I am creating multiple relationships in one query. If a match is not found for the first relationship the second one is not created. If both matches exist then both relationships work.
Example:
Assume that 'MATCH1ID' below does not exist but 'MATCH2ID' does. Why does this happen?
DOES NOT WORK
MERGE (NewRecord:OBJECTNAME { Id: 'ABZDEFG' })
SET NewRecord.name='NEWNAME'
WITH NewRecord
MATCH (a)
WHERE a.Id = 'MATCH1ID'
CREATE (a)-[ar:Relationship1]->(NewRecord)
WITH NewRecord MATCH (b)
WHERE b.Id = 'MATCH2ID'
CREATE (b)-[br:Relationship2]->(NewRecord)
(If I switch the order of the node that does exist to be first in the order it works)
WORKS
MERGE (NewRecord:OBJECTNAME { Id: 'ABZDEFG' })
SET NewRecord.name='NEWNAME'
WITH NewRecord
MATCH (b)
WHERE b.Id = 'MATCH2ID'
CREATE (b)-[br:Relationship2]->(NewRecord)
WITH NewRecord
MATCH (a)
WHERE a.Id = 'MATCH1ID'
CREATE (a)-[ar:Relationship1]->(NewRecord)
You can try using a OPTIONAL MATCH instead of a simple MATCH:
MERGE (NewRecord:OBJECTNAME { Id: 'ABZDEFG' })
SET NewRecord.name='NEWNAME'
WITH NewRecord
OPTIONAL MATCH (a)
WHERE a.Id = 'MATCH1ID'
FOREACH(x IN (CASE WHEN a IS NULL THEN [] ELSE [1] END) |
CREATE (a)-[ar:Relationship1]->(NewRecord)
)
WITH NewRecord
OPTIONAL MATCH (b)
WHERE b.Id = 'MATCH2ID'
FOREACH(x IN (CASE WHEN b IS NULL THEN [] ELSE [1] END) |
CREATE (b)-[br:Relationship2]->(NewRecord)
)
Also, this query uses a trick with FORACH and CASE WHEN to handle conditions. In this case, the CREATE statement is executed only when a or b variables are not null.
See Neo4j: LOAD CSV - Handling Conditionals.
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
My graph contains a set of nodes which are enumerated using a dedicated field fid. I want to update this enumeration periodically.
My current approach is to reset the enumeration and execute multiple statements that increase the fid for each node.
1. (f:File) set f.fid = -1
for(int i = 0; i < count ; i++) {
2. (f:File) set f.fid = i where id(f) = nodeId
}
I guess it should be possible to execute this task using a single cypher statement using the foreach clause.
MATCH p=(f:File)
FOREACH (n IN nodes(p)| SET f.fid = -1 )
I was looking for something similar to this statement.
MATCH (f:File)
WITH COLLECT(f) AS fs
WITH fs, i = 0
FOREACH (f in fs, i=i+1| SET f.fid = i ) return f.fid, f.name
Based on the following console set : http://console.neo4j.org/r/447qni
The following query seems to do the trick :
MATCH (f:File)
WITH collect(f) as f, count(f) AS c
UNWIND range(0,c-1) AS x
WITH f[x] AS file,x
SET file.iteration = x+1