several relationships from a node to another node - neo4j

I'm new to neo4j. I have a .csv file with two columns separated by ",". The first column contains first names and the 2nd column contains the last names:
Lname,Fname
Brown,Helen
Right,Eliza
Green,Helen
Pink,Kate
Yellow,Helen
I want to create nodes for Lname column and nodes for Fname column. For the rows that have the same Fname, I want to connect Lname to the corresponding Fname. For example I want to have a "Helen" node that three nodes "Brown", "Green" and "Yellow" connected to "Helen". I also want to connect "Fname" nodes to a "central node". I have written this code:
LOAD CSV WITH HEADERS FROM 'file:///names.csv' AS row
WITH row.Fname AS first, row.Lname AS last
MERGE (p:la {last: last})
MERGE (o:fi {first: first})
MERGE (c:central {name: "central node"})
MERGE (c)-[r:CONTAINS {first:first}]->(o)-[rel:CONTAINS {first: first}]->(p)
RETURN count(o)
when I run this code and display the output using this query:
MATCH (c:central)-[r:CONTAINS]->(o:fi)-[rel:CONTAINS]->(p:la)
RETURN c, r, o, rel, p
I receive this graph as output:
As you see according to the number of last names, I have the same number of relationships to the first names, For example I have 3 relationships from "central node" to "Helen", but I want only one relationship from "central node" to "Helen". What's wrong here?

The answer lies in your final MERGE clause.
MERGE (c)-[r:CONTAINS {first:first}]->(o)-[rel:CONTAINS {first: first}]->(p)
Neo4j will take this entire pattern and ensure it is unique. Since each time it is invoked (due to the last name changing) the whole thing is created. If you would like to have a single relationship from the central to the first name nodes then you need to split it up into two separate parts. Using the following the first MERGE will only create the central-first relationship once.
MERGE (c)-[r:CONTAINS {first:first}]->(o)
MERGE (o)-[rel:CONTAINS {first: first}]->(p)

Related

can you add a value as the relationship type from the csv

eg [:owes] instead of this i would like the amount they owe (row.amount)
couldnt come up with much
Below simple cypher script will load the csv file then create a relationship type based on the row.amount and uses APOC (awesome procedure)
LOAD CSV WITH HEADERS FROM "file:///testing.csv" AS row
MERGE (p:Person {name: row.fromPerson})
MERGE (m:Person {name: row.toPerson})
WITH p, m, row
CALL apoc.create.relationship(p, row.amount, {amount: row.amount}, m) YIELD rel
RETURN p, m, rel;
Sample testing.csv:
fromPerson,amount,toPerson
"Tom Hanks",100,"Meg Ryan"
Sample Result:
You wouldn't want to have this as relationship type. The standard way of storing such information is to keep the OWES label as a type and store the amount value as relationship property.
Example statement :
LOAD CSV FROM file:///... AS row
MERGE (from:User {id: row.from_id})
MERGE (to:User {id: row.to_id})
MERGE (from)-[r:OWES]->(to)
SET r.amount = row.amount
If for visualisation purposes you want to see the amount as the caption for the relationship in the Neo4j browser, you can do the following.
Click on the relationship type in the panel on the right
Select the property you want to use as caption

How to return nodes that have only one given relationship

I have nodes that represent documents, and nodes that represent entities. Entities can be referenced in document, if so, they are linked together with a relationship like that :
(doc)<-[:IS_REFERENCED_IN]-(entity)
The same entity can be referenced in several documents, and a document can reference several entities.
I'd like to delete, for a given document, every entity that are referenced in this given document only.
I thought of two different ways to do this.
The first one uses java to make a foreach and would basically be something like that :
List<Entity> entities = MATCH (d:Document {id:0})<-[:IS_REFERENCED_IN]-(e:Entity) return e
for (Entity entity : entities){
MATCH (e:Entity)-[r:IS_REFERENCED_IN]->(d:Document) WITH *, count(r) as nb_document_linked WHERE nb_document_linked = 1 DELETE e
}
This method would work but i'd like not to use a foreach or java code to make it. I'd like to do it in one cypher query.
The second one uses only one cypher query but doesn't work. It's something like that :
MATCH (d:Document {id:0})<-[:IS_REFERENCED_IN]-(e:Entity)-[r:IS_REFERENCED_IN]->(d:Document) WITH *, count(r) as nb_document_linked WHERE nb_document_linked = 1 DELETE e
The problem here is that nb_document_linked is not unique for every entity, it is a unique variable for all the entities, which mean it'll count every relationship of every entity, which i don't want.
So how could I make a kind of a foreach in my cypher query to make it work?
Sorry for my english, I hope the question is clear, if you need any information please ask me.
You can do something like:
MATCH (d:Document{key:1})<-[:IS_REFERENCED_IN]-(e:Entity)
WITH e
MATCH (d:Document)<-[:IS_REFERENCED_IN]-(e)
WITH COUNT (d) AS countD, e
WHERE countD=1
DETACH DELETE e
Which you can see working on this sample data:
MERGE (a:Document {key: 1})
MERGE (b:Document {key: 2})
MERGE (c:Document {key: 3})
MERGE (d:Entity{key: 4})
MERGE (e:Entity{key: 5})
MERGE (f:Entity{key: 6})
MERGE (g:Entity{key: 7})
MERGE (h:Entity{key: 8})
MERGE (i:Entity{key: 9})
MERGE (j:Entity{key: 10})
MERGE (k:Entity{key: 11})
MERGE (l:Entity{key: 12})
MERGE (m:Entity{key: 13})
MERGE (d)-[:IS_REFERENCED_IN]-(a)
MERGE (e)-[:IS_REFERENCED_IN]-(a)
MERGE (f)-[:IS_REFERENCED_IN]-(a)
MERGE (g)-[:IS_REFERENCED_IN]-(a)
MERGE (d)-[:IS_REFERENCED_IN]-(b)
MERGE (e)-[:IS_REFERENCED_IN]-(b)
MERGE (f)-[:IS_REFERENCED_IN]-(c)
MERGE (g)-[:IS_REFERENCED_IN]-(c)
MERGE (j)-[:IS_REFERENCED_IN]-(a)
MERGE (h)-[:IS_REFERENCED_IN]-(a)
MERGE (i)-[:IS_REFERENCED_IN]-(a)
MERGE (g)-[:IS_REFERENCED_IN]-(c)
MERGE (k)-[:IS_REFERENCED_IN]-(c)
MERGE (l)-[:IS_REFERENCED_IN]-(c)
MERGE (m)-[:IS_REFERENCED_IN]-(c)
On which it removes 3 Entities.
The first MATCH finds the entities that are attached to your input doc, and the second MATCH finds the number of documents that each of these entities is connected to.

Merging Nodes in Neo4j

I am trying merge two neo4j graphs using CYPHER. The first one is the example of Countries and their Capitals. The second one is a sample example I created.
WITH "https://gist.githubusercontent.com/jimmycrequer/7aa867900d0cf0b9588d4354f09cb286/raw/countries.json" AS url
CALL apoc.load.json(url) YIELD value AS v
MERGE (c:Country {name: v.name})
SET c.population = v.population, c.area = v.area
CREATE (capital:City {name: v.capital})
CREATE (c)<-[:IS_CAPITAL_OF]-(capital)
FOREACH (n IN v.neighbors |
MERGE (neighbor:Country {name: n})
MERGE (c)-[:IS_NEIGHBOR_OF]-(neighbor)
)
To this, I'm trying to add my graph
//Manufacturers
MERGE (BMW:Manufacturer {name:"BMW" , headquarters :"Germany" , employees :100306,factories:25 ,revenue:95.8 ,production:1668982 ,sales: 1688982 })
MERGE(Germany:Country)-[:MANUFACTURERS]->(BMW)
The Node Germany has the following properties
id:103, area:357022, name:Germany, population:8288000
When, I try to look for the final output. I see there is an empty blank node created for the relationship [:MANUFACTURERS] and a node BMW is created.
Change your second query a bit. Just because you name the node variable Germany, Neo4j doesnt know you want to match the country with the name property Germany.
And in most cases you should merge or match nodes first and only then add tje relationship between the two
MERGE (BMW:Manufacturer {name:"BMW" , headquarters :"Germany" , employees :100306,factories:25 ,revenue:95.8 ,production:1668982 ,sales: 1688982 })
MERGE (Germany:Country{name:'Germany})
MERGE (Germany)-[:MANUFACTURERS]->(BMW)

Import data from 2 csv files in neo4j

As a continue to this post in which I completely explained what I'm supposed to do, in case my central node is located in another .csv file, how can I import it in my graph?
The content of names.csv (2 columns: Lname & Fname):
Lname,Fname
Brown,Helen
Right,Eliza
Green,Helen
Pink,Kate
Yellow,Helen
The content of central.csv (2 columns: central & value):
central,value
cent1,10
I tried something like this:
LOAD CSV WITH HEADERS FROM 'file:///central.csv' AS frow
MERGE (c:center {name: frow.central})
WITH *
LOAD CSV WITH HEADERS FROM 'file:///names.csv' AS srow
WITH srow.Fname AS first, srow.Lname AS last
MERGE (p:la {last: last})
MERGE (o:fi {first: first})
MERGE (c)-[r:CONTAINS {first:first}]->(o)
MERGE (o)-[rel:CONTAINS {first: first}]->(p)
RETURN count(o)
but it didn't work for me. It created the central node for me, but my central node is not connected to first nodes as it was supposed to. What's wrong. I wanted it to be like this:
Your second WITH clause does not contain c, so c becomes an unbound variable after that clause.
Change this:
WITH srow.Fname AS first, srow.Lname AS last
to this:
WITH c, srow.Fname AS first, srow.Lname AS last
By the way, your query will only work as you expect if central.csv contains just one data row (as it does currently).

How to merge tree in neo4j

Let's say I have a database with named nodes and that the database is either empty or has the following content:
I now need a neo4j statement, that inserts exactly that tree structure, if it does not exists already in the database.
For simple node pair merge, I could use something like
MERGE ({name: 'A'})-[:R1]->({name: 'B'})
But I want the tree structure. How do I add C here?
Firstly, you have to add a label on your tree node (Tree in my above example) and create a unique constraint on the name attribute like this :
CREATE CONSTRAINT ON (n:Tree) ASSERT n.name IS UNIQUE;
Then you can use this script to create the C node and the others is they don't exist :
MERGE (a:Tree {name: 'A'})
MERGE (b:Tree {name: 'B'})
MERGE (c:Tree {name: 'C'})
MERGE (a)-[:R1]->(b)
MERGE (a)-[:R2]->(c);
As you can see you have to use one MERGE per node, and then one MERGE per relationship.

Resources