cancel
Showing results for 
Search instead for 
Did you mean: 

Head's Up! These forums are read-only. All users and content have migrated. Please join us at community.neo4j.com.

Creating a new node between two existing nodes with the same relationship type

gdb_ONE
Node Link

Hi ,

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} 

2 ACCEPTED SOLUTIONS

Cobra
Ninja
Ninja

Hello @gdb_ONE 🙂

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

Regards,

Cobra

View solution in original post

Hello @gdb_ONE 

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.

Regards,

Cobra

View solution in original post

8 REPLIES 8

Cobra
Ninja
Ninja

Hello @gdb_ONE 🙂

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

Regards,

Cobra

gdb_ONE
Node Link

Thank you for your reply :).

I had two follow-up doubts/questions:

I wanted to know what 'IN TRANSACTION' does as I am not well versed in apoc statements.

I tried to add a name to the new node that was being created in the statement Create (n:Node {name:'F', lvl:'2'}) but got this error :"

Invalid input 'F': expected whitespace, '.', node labels or rel types, '[', '^', '*', '/', '%', '+', '-', "=~", IN, STARTS, ENDS, CONTAINS, IS, '=', "<>", "!=", '<', '>',/ "<=", ">=", AND, XOR, OR, ',' or ')' (line 4, column 32 (offset: 152))

is this because of apoc statement? cause i could normally add properties like this to nodes

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

Regards,

Cobra

Hello @Cobra ,

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 

eg A=C -> A=B=C

Hello @Cobra , 

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 )

it gives this error

Failed to invoke procedure `apoc.cypher.doIt`: Caused by: org.neo4j.exceptions.SyntaxException: Invalid input 'null': expected
  ","
  "CALL"
  "CREATE"
  "DELETE"
  "DETACH"
  "FOREACH"
  "LIMIT"
  "LOAD"
  "MATCH"
  "MERGE"
  "OPTIONAL"
  "ORDER"
  "REMOVE"
  "RETURN"
  "SET"
  "SKIP"
  "UNION"
  "UNWIND"
  "USE"
  "WHERE"
  "WITH"
  <EOF> (line 1, column 35 (offset: 34))
" WITH  $`a` as `a` ,  $`b` as `b` null"

Hello @gdb_ONE 

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.

Regards,

Cobra

gdb_ONE
Node Link

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 🙂