How to set a list attribute to a node? - neo4j

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.

Related

Neo4J Insertion taking time

I have a query which is taking the long time to insert in neo4j roughly the query looks like following :
create index on :symaccess_symdev(dir_port);
create index on :symaccess_symdev(host_lun);
create index on :symaccess_symdev(ini_tiator_group_name);
create index on :symaccess_symdev(sym_dev);
CALL apoc.load.json('file:////root/output/1530115956414/dev.json') YIELD
value AS row UNWIND row.symdev AS symdevs
MERGE (accesssymdev:symaccess_symdev {
sym_dev: symdevs.sym_dev,
host_lun: symdevs.host_lun,
ini_tiator_group_name: symdevs.ini_tiator_group_name,
dir_port: symdevs.dir_port
})
ON CREATE SET
accesssymdev.attr_percentage = symdevs.attr_percentage,
accesssymdev.cap_mb = toFloat(symdevs.cap_mb),
accesssymdev.physicaldevicename = symdevs.physicaldevicename;
Assuming that the sym_dev property value is unique for every symaccess_symdev node, then this query may be faster:
CALL apoc.load.json('file:////root/output/1530115956414/dev.json') YIELD
value AS row UNWIND row.symdev AS symdevs
MERGE (a:symaccess_symdev {sym_dev: symdevs.sym_dev})
ON CREATE SET
a.host_lun = symdevs.host_lun,
a.ini_tiator_group_name = symdevs.ini_tiator_group_name,
a.dir_port = symdevs.dir_port,
a.attr_percentage = symdevs.attr_percentage,
a.cap_mb = toFloat(symdevs.cap_mb),
a.physicaldevicename = symdevs.physicaldevicename;
A MERGE will only use at most one index, so your current query will cause the Cypher planner to pick one index (out of the 4 that are applicable). After using that index to generate a set of candidate nodes, it would still need to check the other 3 properties for each candidate node. If it had picked an index that is not very selective (because there tends to be many nodes with the same property value), then a lot of work would need to be done per MERGE.
Assuming that the sym_dev property value is unique, the above query simplifies the MERGE so that it will quickly discover whether the wanted symaccess_symdev node existed, and without needing to check any other properties.

Can't create node with labels or properties here. The variable is already declared in this context in Neo4j

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'})

Q: How to include a WHERE clause in a MERGE statement in Neo4j

I have an object which has a unique but not required property, i.e. a Facebook ID. If I insert another of the object with the same name and there is an object without a Facebook ID then I assume they are the same. If there is an object with the same name but a different Facebook ID then I assume they're different and create a new object.
I've tried various statements based off the Cypher documentation but couldn't get any of them to be valid syntax.
While this example is not valid I think it gets the point across of what I'm trying to do:
MERGE (t:Thing {name: 'My Not Always Unique Name'})
WHERE EXISTS(t.facebook_id) AND t.facebook_id <> '111111111'
ON CREATE SET t.name = 'My Not Always Unique Name',
t.facebook_id = '111111111',
t.another_property = 'blah'
ON MATCH SET t.another_property = 'blah'
RETURN t;
I believe I have an answer for this which depends on the UUIDs that I'm setting to the id property.
OPTIONAL MATCH (t:Thing {name: 'My Not Always Unique Name'}) WHERE t.facebook_id IS NULL OR t.facebook_id = '1111111'
WITH t
MERGE (s:Thing {id: COALESCE(t.id, 'e8344f24-faff-443a-ac48-b757381eddb8')})
ON MATCH SET s.name = 'My Not Always Unique Name', s.facebook_id = '1111111'
ON CREATE SET s.name = 'My Not Always Unique Name', s.facebook_id = '1111111' RETURN s;
Not sure if this is the best way to do this but it works for me. I'll leave this open for a little to see if anyone has a better answer.
One negative side-effect is if I'm inserting something that doesn't have a facebook_id it will need a separate merge statement.

Neo4j add nodes only on merge create

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

Neo4j create if not exist otherwise update

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".

Resources