I am trying to add a dummy node between two nodes and copy the relationship type on its outgoing and incoming edges. My nodes have a lvl property and if a lvl 1 is directly connected to a lvl 3 I add a dummy node with lvl 2 in between. The relationship type isnt defined and may change between different node pairs.
EG : A{lvl:1} -[*]-> C[lvl:3}
I need to add B with lvl :2 : A{lvl:1} -[*]->B{lvl:2}-[*]-> C[lvl:3}
This query works on the version 4.4 at least of Neo4j with the APOC plugin but it should do what you asked:
MATCH (a:Node {lvl: 1})-[r]->(b:Node {lvl: 3})
CALL {
WITH a, r, b
CALL apoc.cypher.doIt('
WITH a, b
CREATE (n:Node {lvl: 2})
MERGE (a)-[:`'+type(r)+'`]->(n)
MERGE (n)-[:`'+type(r)+'`]->(b)
RETURN *
', {a:a, b:b})
YIELD value
DELETE r
} IN TRANSACTIONS
I have to use apoc.cypher.doIt() procedure since we want to execute a writing transaction and that it's the only wait to setup the type dynamically in Cypher.
If you execute this query in Neo4j Browser, you have to add :auto front of the query. The subquery is used to optimized the process if you have to scan the whole database
It's just a problem of quotation marks, you have to use "F" and not 'F':
MATCH (a:Node {lvl: 1})-[r]->(b:Node {lvl: 3})
CALL {
WITH a, r, b
CALL apoc.cypher.doIt('
WITH a, b
CREATE (n:Node {lvl: 2, name: "F"})
MERGE (a)-[:`'+type(r)+'`]->(n)
MERGE (n)-[:`'+type(r)+'`]->(b)
RETURN *
', {a:a, b:b})
YIELD value
DELETE r
} IN TRANSACTIONS
I was trying to update the query for a case where there are two or more relationships between the nodes A and C and I wanted a node B with the same amount of relationships coming in and going out without creating multiple B
I updated your query to insert node between nodes with 2 relationship between them but it gives an error in some cases while runs for some
MATCH (a:A {lvl:"1"})-[r]->(b:A {lvl:"3"})
WITH a, collect(r) as r, b
CALL apoc.cypher.doIt('
WITH a, b
CREATE (n:A {name:"F",lvl: "2"})
MERGE (a)-\[:\`'+type(r\[0\])+'\`\]->(n)
MERGE (n)-\[:\`'+type(r\[0\])+'\`\]->(b)
MERGE (a)-\[:\`'+type(r\[1\])+'\`\]->(n)
MERGE (n)-\[:\`'+type(r\[1\])+'\`\]->(b)
RETURN \*
', {a:a, b:b})
YIELD value
DELETE r\[0\],r\[1\] (had to remove call in transactions as i couldnt write collect in with clause )
MATCH (a:Node {lvl: 1})-[r]->(b:Node {lvl: 3})
WITH a, b, collect(r) AS relations
CALL {
WITH a, b, relations
CREATE (n:Node {lvl: 2, name: "F"})
WITH a, b, n, relations
UNWIND relations AS r
CALL apoc.merge.relationship(a, type(r), {}, {}, n, {}) YIELD rel WITH b, n, r
CALL apoc.merge.relationship(n, type(r), {}, {}, b, {}) YIELD rel WITH r
DELETE r
} IN TRANSACTIONS
Don't forget to add :auto front of the query if you execute it from the browser.
Thanks a lot @Cobra I am really starting to understand how to search for apoc procedures as per my requirement. Just one question the code works for both single and double relationships present between two nodes.. was there a reason you used cypher.do.it the first time for single relationships ?
I feel you did it because there wasnt a need to introduce collect, unwind if I specified only one relationship but do correct me if I am wrong
No problem When I first replied to your topic I used the apoc.cypher.doIt() procedure but for the new answer I remembered there was an apoc.merge.relationship() procedure to dynamically create relationships. I think apoc.merge.relationship() is less dirty than apoc.cypher.doIt() for your case