create nodes / relationship pointing to the same city - neo4j

I have an empty neo4j database. I want the city{val:"new york"} node to only have one instance, not two. What is the correct way to CREATE these nodes and relationships so that john and sam are pointing to the same city{val:"new york"} node?
CREATE
(p:person{name:"john"}),
(c:city{val:"new york"}),
(p)-[:LIVES_IN]->(c)
CREATE
(p:person{name:"sam"}),
(c:city{val:"new york"}),
(p)-[:LIVES_IN]->(c)
The data I am importing is in a csv file. I need some way to only create the city if it does not already exist. I tried to replace CREATE with MERGE, but the syntax is unclear.

It is simpler (and safer, since you don't always know if the data already exists) to just always use MERGE in cases where there can be duplicate attempts to create data that you want to be unique.
These 2 blocks of Cypher statements will not create duplicate nodes/relationships, even if you reverse the order (or if the DB already has some of the same data).
MERGE (p:person{name:"john"})
MERGE (c:city{val:"new york"})
MERGE (p)-[:LIVES_IN]->(c);
MERGE (p:person{name:"sam"})
MERGE (c:city{val:"new york"})
MERGE (p)-[:LIVES_IN]->(c);

Answering my own question. Each line needs its own MERGE clause.
CREATE
(p:person{name:"john"}),
(c:city{val:"new york"}),
(p)-[:LIVES_IN]->(c)
MERGE (p:person{name:"sam"})
MERGE (c:city{val:"new york"})
MERGE (p)-[:LIVES_IN]->(c)
Good related resource...https://neo4j.com/blog/common-confusions-cypher/

Related

Neo4j: how to avoid node to be created again if it is already in the database?

I have a question about Cypher requests and the update of a database.
I have a python script that does web scraping and generate a csv at the end. I use this csv to import data in a neo4j database.
The scraping is done 5 times a day. So every time a new scraping is done the csv is updated, new data is added to the the previous csv and so on.
I import the data after each scraping.
Actually when I import the data after each scraping to update the DB, I have all the nodes created again even if it is already in the DB.
For example the first csv gives 5 rows and I insert this in Neo4j.
Next the new scraping gives 2 rows so the csv has now 7 rows. And if I insert the data I will have the first five rows twice in the DB.
I would like to have everything unique and not added if it is already in the database.
For example when I try to create node ARTICLE I do this:
CREATE (a:ARTICLE {id:$id, title:$title, img_url:$img_url, link:$link, sentence:$sentence, published:$published})
I think MERGE instead of CREATE should solve the solution, but it doesn't and I can't figure it out why.
How can I do this ?
A MERGE clause will create its entire pattern if any part of it does not already exist. So, for a MERGE clause to work reasonably, the pattern used with it must only specify the minimum data necessary to uniquely identify a node (or a relationship).
For instance, assuming ARTICLE nodes are supposed to have unique id properties, then you should replace your CREATE clause:
CREATE (a:ARTICLE {id:$id, title:$title, img_url:$img_url, link:$link, sentence:$sentence, published:$published})
with something like this:
MERGE (a:ARTICLE {id:$id})
SET a += {title:$title, img_url:$img_url, link:$link, sentence:$sentence, published:$published}
In the above example, the SET clause will always overwrite the non-id properties. If you want to set those properties only when the node is created, you can use ON CREATE before the SET clause.
Use MERGE instead of CREATE. You can use it for both nodes and relationships.
MERGE (charlie { name: 'Charlie Sheen', age: 10 })
Create a single node with properties where not all properties match any existing node.
MATCH (a:Person {name: "Martin"}),
(b:Person {name: "Marie"})
MERGE (a)-[r:LOVES]->(b)
Finds or creates a relationship between the nodes.

Neo4j Data Import Slowness

I have to load around 5M Records in the Neo4j DB so I broke the excel into the chunks of 100K the Data is in Tabular Format and I am using CyperShell for that but seems like it has been more than 8 hours and it's still stuck on the first chunk
I'm Using
USING PERIODIC COMMIT
LOAD CSV WITH HEADERS from 'file://aa.xlsx' as row
MERGE (p1:L1 {Name: row.sl1})
MERGE (p2:L2 {Name: row.sl2})
MERGE (p3:L3 {Name: row.sl3, Path:row.sl3a})
MERGE (p4:L4 {Name: row.sl4})
MERGE (p5:L4 {Name: row.tl1})
MERGE (p6:L3 {Name: row.tl2})
MERGE (p7:L2 {Name: row.tl3, Path:row.tl3a})
MERGE (p8:L1 {Name: row.tl4})
MERGE (p1)-[:s]->(p2)-[:s]->(p3)-[:s]->(p4)-[:it]->(p5)-[:t]->(p6)-[:t]->(p7)-[:t]->(p8)
Can Anyone Suggest me the changes or alternate Method to load the data in faster way
Data in Excel Format
For importing a large amount of data, you should consider using the import tool instead of Cypher's LOAD CSV clause. That tool can only import into a previously unused database.
If you still want to use LOAD CSV, you need to make some changes.
You are using MERGE improperly, and are probably generating many duplicate nodes and relationships as a result. You may find this answer instructive.
A MERGE clause's entire pattern will be created if anything in
the pattern does not already exist.
So, your last MERGE pattern, with its seven relationships, is especially dangerous. It should be split into seven MERGE clauses with individual relationships.
Also, a MERGE pattern that specifies multiple properties is likely bad as well. For example, if all L3 nodes have a unique Name value, then it would be safer to replace this:
MERGE (p3:L3 {Name: row.sl3, Path:row.sl3a})
with something like the following:
MERGE (p3:L3 {Name: row.sl3})
ON CREATE SET p3.Path = row.sl3a
In the above snippet, if the node already exists but row.sl3a is different than the existing Path value, then no additional node is created. In addition, since the node already existed, the ON CREATE option does not execute its SET clause, leaving the original Path value unchanged. You could also choose to use ON MATCH instead, or even just call SET directly if you want to set the value no matter what.
To avoid having to scanning through all the nodes with a given label every time MERGE needs to find an existing node, you should create an index or uniqueness constraint for every label/property pair of every node that you are MERGEing:
:L1(Name)
:L2(Name)
:L3(Name)
:L4(Name)

Neo4J - Creating Relationship on existing nodes

I am new to Neo4J and I am looking to create a new relationship between an existing node and a new node.
I have a university node, and person node.
I am trying to assign a new person to an existing university.
I am trying to following code:
MATCH (p:Person {name:'Nick'}), (u:University {title:'Exeter'}) CREATE (p)-[:LIKES]->(u)
So in the above code: MATCH (p:Person {name:'Nick'}) is the new user
AND (u:University {title:'Exeter'}) is the exisiting univeristy.
But it is coming back (no changes, no rows)
I have even tried the query without the MATCH part but no luck either.
I have looked at few similar answers but they didn't seem to work either.
Any help would be very much appreciated. Thank you.
Match before u create new one, as suggested in the comments!
MATCH(u:University {title:'Exeter'})
CREATE(p:Person {name:'Nick'})
CREATE(p)-[w:LIKES]->(u)
return w
You could also use a MERGE statement as per the docs:
MERGE either matches existing nodes and binds them, or it creates new data and binds that. It’s like a combination of MATCH and CREATE that additionally allows you to specify what happens if the data was matched or created.
You would do a query like
MERGE (p:Person {name:'Nick'})-[:LIKES]->(u:University {title:'Exeter'})
It is because when you match you search for a nodes in your db. The db says i can't make the realtion "when the nodes dont exist".
Luckily there is something called merge it is like a match +create when he does not find the whole path he creates it.
it should be something like merge 'node1' merge'node2' create(node1)[]->(node2)

Cypher: merge path without duplicate relationships

I am currently implementing a graph database in which persons are allocated to projects (of a customer) using an allocation node. Customers or Projects may or may not exist already, the Allocation node should be unique (each Allocation node can only have one incoming and one outgoing relationship). The code below works, but duplicates the Project->Customer relationship when both already exists in the database. How can I prevent this?
MATCH (p:Person {id:1})
MERGE (c:Customer {id:1})
MERGE (pr:Project {id:1})
CREATE (p)-[:HAS_ALLOCATION]->(a:Allocation)-[:ON_PROJECT]->(pr)-[:HAS_CUSTOMER]->(c)
RETURN a,p,pr,c;
You should try both MERGE and CREATE UNIQUE in place of your CREATE clause and see if that fixes your issue.

Avoiding duplication on nodes with same value neo4j

I have two column in csv file, emp_id and mngr_id. The relationship is (emp_id)-[:WORKS_UNDER]->(mngr_id). I want to merge all those nodes where emp_id=mngr_id. How to do that while creating nodes itself?
If I understand correctly, you're looking to ensure that you avoid creating duplicate relationships when iterating over the CSV data and avoid entering a relationship where a person works for themselves.
To avoid creating a relationship where emp_id and mngr_id identify the same person, I would suggest filtering the CSV before processing it to enter the data. It should be much easier to omit any lines in the CSV file where the emp_id and mngr_id are the same value before passing it to Neo4j.
Next, if you're using Cypher to do the importing, something like this may be useful:
MERGE (emp:Person{id:'emp_id'}) MERGE (mgr:Person{id:'mngr_id'}) MERGE (emp)-[:WORKS_UNDER]->(mgr) RETURN emp,mgr
Note that if you run the above query multiple times in a block statement then you'll need unique identifiers for emp and mgr in each query.
Merge is explained well in the Neo4j docs: http://docs.neo4j.org/chunked/stable/query-merge.html

Resources