I need to create a relation between two users once, and update its properties since then. Is there a way to do something like "create if not exist otherwise update" in Neo4j using Cypher?
MERGE (u1:User)-[r:REL]->(u2:User)
ON CREATE SET
u1.prop1 = val1,
u2.prop2 = val2,
r.prop3 = val3
ON MATCH SET
u1.prop1 = newVal1,
u2.prop2 = newVal2,
r.prop3 = newVal3
Have a look at the Neo4j docs for "MERGE".
Related
This seems like a simple use case but I'm having trouble locating an example in the docs.
I want to do the following:
MERGE(node:Graph{id:{id}})
ON CREATE SET node.firstseen = timestamp(),
SET node.id = {id},
node.list = [list]
Examples of this would be appreciated, thanks!
You have a comma before your SET clause:
ON CREATE SET node.firstseen = timestamp(),
^
The correct query is
MERGE (node:Graph {id:$id})
ON CREATE SET node.firstseen = timestamp()
SET
node.list = $list
You don't need to set the id field, the MERGE takes care of this. The list field will be set every time you call the query, the firstseen timestamp only when the node doesn't exist.
Assuming you pass id and list as parameters:
MERGE (node:Graph {id: $id})
ON CREATE SET
node.firstseen = timestamp(),
node.list = $list
You cannot have a SET clause within another SET clause. Besides, it is unnecessary to SET node.id = $id anyway, since your MERGE already guarantees that property has that value.
I tried to run below cypher query in Neo4j(3 Merge Statement in once)
MERGE (paymentinstrument{SENDER_CREDITCARD:'123444'})-[rPAYMENTINSTRUMENT:PROFILECHANGE_PI{}]->( profilechange )
ON CREATE SET rPAYMENTINSTRUMENT.CREATETIMESTAMP = toInt('1413911269726')
ON MATCH SET rPAYMENTINSTRUMENT.UPDATETIMESTAMP = toInt('1413911269726')
MERGE (profilechange{PROFILECHANGEIDENTIFIER:'ABCD'})-[rPROFILECHANGEDEVICE:HAS_DEVICE{}]->( device )
ON CREATE SET rPROFILECHANGEDEVICE.CREATETIMESTAMP = toInt('1413911269726')
ON MATCH SET rPROFILECHANGEDEVICE.UPDATETIMESTAMP = toInt('1413911269726')
MERGE (profilechange{PROFILECHANGEIDENTIFIER:'ABCD'})-[rPROFILECHANGEIPADDRESS:HAS_IP{}]->( ipaddress )
ON CREATE SET rPROFILECHANGEIPADDRESS.CREATETIMESTAMP = toInt('1413911269726')
ON MATCH SET rPROFILECHANGEIPADDRESS.UPDATETIMESTAMP = toInt('1413911269726')
which encountered below error
Can't create node profilechange with labels or properties here. The
variable is already declared in this context
Does anyone have idea or workaround for this issue ?Thanks
You have two merges starting with
MERGE (profilechange{PROFILECHANGEIDENTIFIER:'ABCD'})
so, its like you are defining two references with the same name
second use, should be
MERGE (profilechange)--
Also, you syntax is bad in the error prone sense.
In "Learning Neo4j", the author :) advises this syntax
(reference:Label{key:'value'})-[r2:RELATIONNAME]->(reference2:Label{you:'got it'})
I'm currently running the following query to update the properties on two nodes and relationships.
I'd like to be able to update 1,000 nodes and the corresponding relationships in one query.
MATCH (p1:Person)-[r1:OWNS_CAR]->(c1:Car) WHERE id(r1) = 3018
MATCH (p2:Person)-[r2:OWNS_CAR]->(c2:Car) WHERE id(r2) = 3019
SET c1.serial_number = 'SERIAL027436', c1.signature = 'SIGNATURE728934',
r1.serial_number = 'SERIAL78765', r1.signature = 'SIGNATURE749532',
c2.serial_number = 'SERIAL027436', c2.signature = 'SIGNATURE728934',
r2.serial_number = 'SERIAL78765', r2.signature = 'SIGNATURE749532'
This query has issues when you run it in larger quantities. Is there a better way?
Thank you.
You could work with a LOAD CSV. Your input would contain the keys (not the ids, using the ids is not recommended) for Person and Car and whatever properties you need to set. For example
personId, carId, serial_number, signature
00001, 00045, SERIAL78765, SIGNATURE728934
00002, 00046, SERIAL78665, SIGNATURE724934
Your query would then be something like :
USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM 'file:///input.csv' AS row
MATCH (p:Person {personId: row.PersonId})-[r:OWNS_CAR]->(c:Car {carId: row.carId})
SET r.serial_number = row.serialnumber, c.signature = row.signature
Note that you should have unique constraints on Person and Car to make that work. You can do thousands (even millions) like that very quickly ...
Hope this helps,
Tom
I want to store some nodes which have integers, how do i make neo4j understand that the characters i am sending are integers.
I tried
MATCH (a:Venture_capital),(b:Organization)
WHERE a.name = "Google" AND int(b.from) = "2004" AND String(b.member) = "John L. Hennessy"
CREATE (a)-[:board_members]->(b)-[:organization]->(a)
and
MATCH (a:Venture_capital),(b:Organization)
WHERE a.name = "Google" AND b.from = int("2004") AND b.member = String("John L. Hennessy")
CREATE (a)-[:board_members]->(b)-[:organization]->(a)
Both are not working. :(
How am i supposed to do that?
Neo4j does not allow me to store datetime and spatial data by default that's weird.
Try:
toFloat(5)
This is a workaround, more details see "Provide a way to set properties with Integer (not Long) values in Cypher #7652" on github.
Use toInt(string)
MATCH (a:Venture_capital),(b:Organization)
WHERE a.name = "Google" AND b.from = toInt("2004")
AND b.member = "John L. Hennessy"
CREATE (a)-[:board_members]->(b)-[:organization]->(a)
I have a cypher that looks like the following
MERGE (col)-[:CONNECTS]->(o)
ON CREATE SET col.name = "SOME NAME"
Now I want to add the following node and relationship only if the merge creates (not matches):
CREATE (o)-[:NEEDS]->(p:anode)
How is this achieved?
There is no built in conditional creation right now in Cypher, I guess it will be added to upcoming versions.
For now you can do a little trick, when creating you set a property on the relationship that will tell it is a new creation, you then do a foreach/case on this property, create the other relationship and remove the property.
Code explains better than words :
MERGE (col)-[r:CONNECTS]->(o)
ON CREATE SET col.name = "SOME NAME", r.new = 1
FOREACH (x IN CASE WHEN r.new = 1 THEN [1] ELSE [] |
CREATE (o)-[:NEEDS]->(p:anode)
)
REMOVE r.new