I've a neo4j schema in which I've 3 nodes. e.g. p,b,c
I want to write a Merge query such that
MERGE (p)-[:has_b]->(b),
MERGE (p)-[:has_c]->(c1),
MERGE (p)-[:has_c]->(c2)
where c1 and c2 are instance of c node having different property values.
i.e. Merge on all three relationships.
If any of 3 merge queries creates a new node, all relationships should use newly created p node.
I can achieve this if I had only two relationships using
(c)<-[:has_c]-MERGE (p)-[:has_b]->(b)
Any suggestions how to do it for 3 relationships as in my case?
FYI, I'm using py2neo which isn't helping at all.
Nodes don't have instances. A node is a node and it has a label.
You can MERGE your nodes first to make sure they exist and that all relationships use the same p:
MERGE (p:LabelA {k: "v"})
MERGE (b:LabelB {k: "v"})
MERGE (c1:LabelC {k: "v"})
MERGE (c2:LabelC {k: "v"})
MERGE (p)-[:has_b]->(b)
MERGE (p)-[:has_c]->(c1)
MERGE (p)-[:has_c]->(c2)
This will create the nodes and relationships only once.
Related
in brief: how can we MERGE multiple nodes and relations just like the way we do with MATCH and CREATE: we can do multiple CREATE or MATCH for nodes or relations, separated with comma, but this action is not allowed with MERGE
in detail: suppose I have two graphs:
G1: (a)-[r1]->(b)<-[r2]-(c)
G2: (a)-[r1]->(b)<-[r3]-(d)
I have G1 inserted in neo4j, and G2 ready to push to db. The normal way to do it is to merge each node pair and then merge the relation; in this example for r1 relation there would be no change in db, since G1 already has the relation, however for the second one, my CQL first create node d then add relation r3
Is there a way to push G2 to db in one step? something like:
MERGE (a), (b), (c), (a)-[r1]->(b)<-[r3]-(d)
to create such result:
(a)-[r1]->(b)<-[r2]-(c)
^
|
[r3]
|
(d)
Not with a single MERGE statement. You would need to follow the pattern of doing a MERGE for each node, then a MERGE for each relationship.
That said, Neo4j does use transactions, so while this is broken into multiple clauses in your Cypher query, the transaction is applied atomically when committed.
Over my Neo4j I want to create this graph:
SO I tried to create some nodes and relationships with:
MERGE (D:POINT {NAME:'d'})<-[:LINKS]-(A:POINT {NAME:'a'})-[:LINKS]->(B:POINT {NAME:'b'})-[:LINKS]->(C:POINT {NAME:'c'})
But I cannot find out how I will create the relationships between D and B points also I cannot find out how I will link the A and C as well.
Do you have any Idea how to do that?
In order to avoid unintentionally creating duplicate nodes and/or relationships, you must invoke MERGE on individual nodes and relationships.
To quote the dev manual:
When using MERGE on full patterns, the behavior is that either the
whole pattern matches, or the whole pattern is created. MERGE will not
partially use existing patterns — it’s all or nothing. If partial
matches are needed, this can be accomplished by splitting a pattern up
into multiple MERGE clauses.
For example, to properly create your graph without any duplicate nodes or relationships:
MERGE (A:POINT {NAME:'a'})
MERGE (B:POINT {NAME:'b'})
MERGE (C:POINT {NAME:'c'})
MERGE (D:POINT {NAME:'d'})
MERGE (A)-[:LINKS]->(B)
MERGE (A)-[:LINKS]->(C)
MERGE (A)-[:LINKS]->(D)
MERGE (B)-[:LINKS]->(C)
MERGE (D)-[:LINKS]->(B)
CREATE seems to be the natural way to me for creating nodes and relationships.
CREATE (D:POINT {NAME:'d'})<-[:LINKS]-(A:POINT {NAME:'a'})
, (A)-[:LINKS]->(B:POINT {NAME:'b'})<-[:LINKS]-(D)
, (B)-[:LINKS]->(C:POINT {NAME:'c'})<-[:LINKS]-(A)
You can do it by doing a MATCH before a MERGE eg. FOR the relationship between A and D do:
MATCH (A:POINT {NAME:'a'}),(B:POINT {NAME:'d'}) MERGE (A)-[:LINKS]->(B)
I am expecting he following query to create nodes (only if exits) and relations by a given source node (1) and a list(2) this way:
MERGE (p1:C9{userId: '1'}) WITH p1, [{userId:"2"}] AS users
FOREACH (user IN users | MERGE
((p1)-[r1:follow]->(:C9 {userId: user.userId})))
Thats the outcome:
Now if I am executing this query again by switching the node id's this way:
MERGE (p1:C9{userId: '2'}) WITH p1, [{userId:"1"}] AS users
FOREACH (user IN users | MERGE
((p1)-[r1:follow]->(:C9 {userId: user.userId})))
We got this:
neo4j duplicated for me the node with id=1. I want it to merge in case of existed nodes.
I expected to see only two nodes connected to each other by merging existed nodes.
any idea what I should fix?
Thanks,
ray.
I normally avoid FOREACH when I can use an UNWIND, so I would start with something like this:
MERGE (p1:C9 {userId: '1'})
WITH p1, [{userId:"2"}] AS users
UNWIND users AS user
MERGE (p1)-[r1:follow]->(:C9 {userId: user.userId})
Sometimes you also want to separate your node creation from your relationship creation. If you do both at the same time, I think that Neo4j can think that you want a unique combination of node (with properties) and relationship.
MERGE (p1:C9 {userId: '1'})
WITH p1, [{userId:"2"}] AS users
UNWIND users AS user
MERGE (p2:C9 {userId: user.userId})
MERGE (p1)-[r1:follow]->(p2)
You can use MERGE within FOREACH.
But you have to understand the semantics of MERGE. It tries to MATCH a full pattern and if it does not find it it will fully CREATE that pattern.
You in your case you try to find a pattern within the context of p1 and not globally and if not found it will create it within the context of p1.
So if you change your query to:
MERGE (p1:C9{userId: '2'})
WITH p1, [{userId:"1"}] AS users
FOREACH (user IN users |
MERGE (p2:C9 {userId: user.userId})
MERGE (p1)-[r1:follow]->(p2)
)
I.e. create p2 first and then MERGE the relationship, it will work.
I have got a question how I can merge the nodes for Documents (Doc1, Doc2 and Doc3), to get nice 3 start schemas.
for index, row in import_ds.iterrows():
ind = ind+1
graph.cypher.execute("MERGE (Document:Document"+str(fnum)+" {Document:\"Doc"+str(fnum)+"\"})")
graph.cypher.execute("MERGE (Type:Type {Type:\""+str(row['type'])+"\"})<-[:HAS_TYPE]-(Word:Word {Word:\""+str(row['token_low'])+"\"})-[:IS_IN]->(Document:Document"+str(fnum)+" {Document:\"Doc"+str(fnum)+"\"})")
(WordType)<-[:HAS_TYPE]-(Word)-[:IS_IN]->(Document) http://www.yottalabs.co.uk/ss.png
[code output - Neo4j browser][1]
you should use parameters, not string substitution
merge tries to find the whole path, if it doesn't it creates the whole path
Usually you would merge the nodes first then the rels:
MERGE (type:Type {Type: {type}})
MERGE (word:Word {Word:{token_low}})
MERGE (document:Document {Document:{doc}})
MERGE (type)<-[:HAS_TYPE]-(word)
MERGE (word)-[:IS_IN]->(document)
Merge data on document node
MERGE (document:Document {Document:{doc}})
SET document.foo = {new_data}.foo, document.bar = {param_bar}
I'm trying to figure out how to run through my database, collect nodes that are similar, and then merge them into a single node and re-direct the previous relationships to the newly created node.
I basically created a bunch of nodes in which some or all of the properties had info, like this:
MERGE (company:Company{Name: 'Ford'})
MERGE (person:Person{Name: 'me'})
MERGE (car:Car{Make:'Ford', Model:'Aerostar', Color:'Blue', Transmission:'Auto'})
but I accidentally duplicated nodes that should have been merged, and instead created new nodes:
MERGE (car:Car{Make:'Ford', Model:'Aerostar', Color:'', Transmission:''})
MERGE (car:Car{Make:'Ford', Model:'Aerostar', Color:'Blue', Transmission:''})
MERGE (car:Car{Make:'Ford', Model:'Aerostar', Color:'Blue', Transmission:'Auto'})
MERGE (person)-[:drives]->(car)-[:parent_company]->(company)
so, what I want do do is take the three (car) nodes I accidentally created, merge all of their properties, delete the extra relationships created by extra nodes and correct the path, so (me) would only have a single [:drives] relationship connected to a single (car) connected by a single [:parent_company] relationship.
here is what I tried, but can't quite figure out:
MATCH p=(car:Car{Make:'Ford', Model:'Aerostar'})<-[:drives]-(person:Person{Name:'me'})
FOREACH (car in nodes (p) | SET Car.Color: 'Blue', Car.Transmission:'Auto')
/////This is where I'm stuck
EDIT: Another Attempt(I get "r already declared error):
START n = node(3) //node id for complete 'aerostar' node
WITH n
MATCH (company)<-[:parent_company]-(car:Car{Make:'Ford', Model:'Aerostar')<-[r:drives]-(person)
WITH n, company, r, car, person
MERGE (person)-[r]->(n)-[:parent_company]->(company)
DELETE car
[EDITED]
Does this work for you?
MATCH (car:Car{Make:'Ford', Model:'Aerostar'})<-[d:drives]-(person:Person{Name:'me'})
DELETE d, car
WITH person
CREATE (car:Car{Make:'Ford', Model:'Aerostar', Color:'Blue', Transmission:'Auto'})<-[d:drives]-(person);
I finally figured out how to do this:
MATCH (car:Car{Make:'Ford', Model:'Aerostar'})<-[d:drives]-(person:Person{Name:'me'})
WITH car,d
SKIP 1
DELETE car,d