Create multiple unique relationships neo4j (single query)












0














I'm currently writing a mongoose plugin to maintain neo4j nodes automatically using the javascript neo4j driver and currently working on mapping updates (the saving part works atm) to a cypher query.



I'm currently stuck at the use case where I want to update multiple relationships between the document (a :Class, saved as node in neo4j) and the updated references (students of type :Person, saved as different nodes in neo4j) while deleting the old relationships tied to the old references (students in this case). This is a result of updating an array of subdocument references in neo4j.



The main problem, besides the cross (cartesian) product that is created in the query, is that the following query creates twice as much relationships as it deletes:



MATCH (doc:Class {m_id: '5bf5b9df11c344021de89395'}), 
(I:Person {m_id: '5bf5b9df11c344021de89393'}),
(II:Person {m_id: '5bf5b9df11c344021de89394'}),
(:Class {m_id: '5bf5b9df11c344021de89395'})-[r]->()
WHERE type(r) IN ["HAS_STUDENT"]
CREATE (doc)-[:HAS_STUDENT]->(I), (doc)-[:HAS_STUDENT]->(II)
DELETE r;


This removes 2 relationships (which is correct), but creates 4 new relationships (should be 2).



Also using a single CREATE in the form of CREATE (I)<-[:HAS_STUDENT]-(doc)-[:HAS_STUDENT]->(II) is not a valid option as this query is created in a for loop and can have an increasing amount of new relationships to be created. (Also the main reason why I want to optimize the query.)



I've had multiple versions of this query which all resulted in the same output. The problem is probably in the WHERE part, because when I use the query below it creates the right amount of relationships. The only missing thing is that it should only delete the old relationships:



MATCH (doc:Class {m_id: '5bf5b9df11c344021de89395'}), 
(I:Person {m_id: '5bf5b9df11c344021de89393'}),
(II:Person {m_id: '5bf5b9df11c344021de89394'})
CREATE (doc)-[:HAS_STUDENT]->(I), (doc)-[:HAS_STUDENT]->(II)
WITH doc
MATCH (doc)-[r]->(n)
WHERE type(r) IN ["HAS_STUDENT"]
DELETE r;


So my main question, besides resolving the problem, is how to efficiently write this query for the described behavior. I use the neo4j driver, so I have availability of using parameters.



NOTE: I and II will later be used as variables to assign unique relationships values, that's why I haven't used a single MATCH for the :Person nodes.



Also, the IN of the relationshiptype in the WHERE clause is used because of the possibility of different types of relationships to be created (and thus the old ones of that type deleted).



At last, I already have looked into UNWIND and FOREACH but can't seem to fit these into the described usecase.










share|improve this question
























  • For this use case, it looks like you should probably use a Neo4j javascript Object Graph Mapper (OGM). Also, do you have the APOC plugin? And to clarify, are you simply trying to remap relationships to end at a different node?
    – Tezra
    Nov 21 '18 at 21:08










  • Well that (The OGM) is actually what I'm trying to create sort of. For the APOC, I don't really want people that use the library to be dependent on APOC as goes for an external OGM. Last part, yes kind of, but I want to combine the create clause with the ones that will create relationships with properties. That's why I thought the best option would be do delete all old relationships and create new ones.
    – Sven Westerlaken
    Nov 23 '18 at 6:28
















0














I'm currently writing a mongoose plugin to maintain neo4j nodes automatically using the javascript neo4j driver and currently working on mapping updates (the saving part works atm) to a cypher query.



I'm currently stuck at the use case where I want to update multiple relationships between the document (a :Class, saved as node in neo4j) and the updated references (students of type :Person, saved as different nodes in neo4j) while deleting the old relationships tied to the old references (students in this case). This is a result of updating an array of subdocument references in neo4j.



The main problem, besides the cross (cartesian) product that is created in the query, is that the following query creates twice as much relationships as it deletes:



MATCH (doc:Class {m_id: '5bf5b9df11c344021de89395'}), 
(I:Person {m_id: '5bf5b9df11c344021de89393'}),
(II:Person {m_id: '5bf5b9df11c344021de89394'}),
(:Class {m_id: '5bf5b9df11c344021de89395'})-[r]->()
WHERE type(r) IN ["HAS_STUDENT"]
CREATE (doc)-[:HAS_STUDENT]->(I), (doc)-[:HAS_STUDENT]->(II)
DELETE r;


This removes 2 relationships (which is correct), but creates 4 new relationships (should be 2).



Also using a single CREATE in the form of CREATE (I)<-[:HAS_STUDENT]-(doc)-[:HAS_STUDENT]->(II) is not a valid option as this query is created in a for loop and can have an increasing amount of new relationships to be created. (Also the main reason why I want to optimize the query.)



I've had multiple versions of this query which all resulted in the same output. The problem is probably in the WHERE part, because when I use the query below it creates the right amount of relationships. The only missing thing is that it should only delete the old relationships:



MATCH (doc:Class {m_id: '5bf5b9df11c344021de89395'}), 
(I:Person {m_id: '5bf5b9df11c344021de89393'}),
(II:Person {m_id: '5bf5b9df11c344021de89394'})
CREATE (doc)-[:HAS_STUDENT]->(I), (doc)-[:HAS_STUDENT]->(II)
WITH doc
MATCH (doc)-[r]->(n)
WHERE type(r) IN ["HAS_STUDENT"]
DELETE r;


So my main question, besides resolving the problem, is how to efficiently write this query for the described behavior. I use the neo4j driver, so I have availability of using parameters.



NOTE: I and II will later be used as variables to assign unique relationships values, that's why I haven't used a single MATCH for the :Person nodes.



Also, the IN of the relationshiptype in the WHERE clause is used because of the possibility of different types of relationships to be created (and thus the old ones of that type deleted).



At last, I already have looked into UNWIND and FOREACH but can't seem to fit these into the described usecase.










share|improve this question
























  • For this use case, it looks like you should probably use a Neo4j javascript Object Graph Mapper (OGM). Also, do you have the APOC plugin? And to clarify, are you simply trying to remap relationships to end at a different node?
    – Tezra
    Nov 21 '18 at 21:08










  • Well that (The OGM) is actually what I'm trying to create sort of. For the APOC, I don't really want people that use the library to be dependent on APOC as goes for an external OGM. Last part, yes kind of, but I want to combine the create clause with the ones that will create relationships with properties. That's why I thought the best option would be do delete all old relationships and create new ones.
    – Sven Westerlaken
    Nov 23 '18 at 6:28














0












0








0







I'm currently writing a mongoose plugin to maintain neo4j nodes automatically using the javascript neo4j driver and currently working on mapping updates (the saving part works atm) to a cypher query.



I'm currently stuck at the use case where I want to update multiple relationships between the document (a :Class, saved as node in neo4j) and the updated references (students of type :Person, saved as different nodes in neo4j) while deleting the old relationships tied to the old references (students in this case). This is a result of updating an array of subdocument references in neo4j.



The main problem, besides the cross (cartesian) product that is created in the query, is that the following query creates twice as much relationships as it deletes:



MATCH (doc:Class {m_id: '5bf5b9df11c344021de89395'}), 
(I:Person {m_id: '5bf5b9df11c344021de89393'}),
(II:Person {m_id: '5bf5b9df11c344021de89394'}),
(:Class {m_id: '5bf5b9df11c344021de89395'})-[r]->()
WHERE type(r) IN ["HAS_STUDENT"]
CREATE (doc)-[:HAS_STUDENT]->(I), (doc)-[:HAS_STUDENT]->(II)
DELETE r;


This removes 2 relationships (which is correct), but creates 4 new relationships (should be 2).



Also using a single CREATE in the form of CREATE (I)<-[:HAS_STUDENT]-(doc)-[:HAS_STUDENT]->(II) is not a valid option as this query is created in a for loop and can have an increasing amount of new relationships to be created. (Also the main reason why I want to optimize the query.)



I've had multiple versions of this query which all resulted in the same output. The problem is probably in the WHERE part, because when I use the query below it creates the right amount of relationships. The only missing thing is that it should only delete the old relationships:



MATCH (doc:Class {m_id: '5bf5b9df11c344021de89395'}), 
(I:Person {m_id: '5bf5b9df11c344021de89393'}),
(II:Person {m_id: '5bf5b9df11c344021de89394'})
CREATE (doc)-[:HAS_STUDENT]->(I), (doc)-[:HAS_STUDENT]->(II)
WITH doc
MATCH (doc)-[r]->(n)
WHERE type(r) IN ["HAS_STUDENT"]
DELETE r;


So my main question, besides resolving the problem, is how to efficiently write this query for the described behavior. I use the neo4j driver, so I have availability of using parameters.



NOTE: I and II will later be used as variables to assign unique relationships values, that's why I haven't used a single MATCH for the :Person nodes.



Also, the IN of the relationshiptype in the WHERE clause is used because of the possibility of different types of relationships to be created (and thus the old ones of that type deleted).



At last, I already have looked into UNWIND and FOREACH but can't seem to fit these into the described usecase.










share|improve this question















I'm currently writing a mongoose plugin to maintain neo4j nodes automatically using the javascript neo4j driver and currently working on mapping updates (the saving part works atm) to a cypher query.



I'm currently stuck at the use case where I want to update multiple relationships between the document (a :Class, saved as node in neo4j) and the updated references (students of type :Person, saved as different nodes in neo4j) while deleting the old relationships tied to the old references (students in this case). This is a result of updating an array of subdocument references in neo4j.



The main problem, besides the cross (cartesian) product that is created in the query, is that the following query creates twice as much relationships as it deletes:



MATCH (doc:Class {m_id: '5bf5b9df11c344021de89395'}), 
(I:Person {m_id: '5bf5b9df11c344021de89393'}),
(II:Person {m_id: '5bf5b9df11c344021de89394'}),
(:Class {m_id: '5bf5b9df11c344021de89395'})-[r]->()
WHERE type(r) IN ["HAS_STUDENT"]
CREATE (doc)-[:HAS_STUDENT]->(I), (doc)-[:HAS_STUDENT]->(II)
DELETE r;


This removes 2 relationships (which is correct), but creates 4 new relationships (should be 2).



Also using a single CREATE in the form of CREATE (I)<-[:HAS_STUDENT]-(doc)-[:HAS_STUDENT]->(II) is not a valid option as this query is created in a for loop and can have an increasing amount of new relationships to be created. (Also the main reason why I want to optimize the query.)



I've had multiple versions of this query which all resulted in the same output. The problem is probably in the WHERE part, because when I use the query below it creates the right amount of relationships. The only missing thing is that it should only delete the old relationships:



MATCH (doc:Class {m_id: '5bf5b9df11c344021de89395'}), 
(I:Person {m_id: '5bf5b9df11c344021de89393'}),
(II:Person {m_id: '5bf5b9df11c344021de89394'})
CREATE (doc)-[:HAS_STUDENT]->(I), (doc)-[:HAS_STUDENT]->(II)
WITH doc
MATCH (doc)-[r]->(n)
WHERE type(r) IN ["HAS_STUDENT"]
DELETE r;


So my main question, besides resolving the problem, is how to efficiently write this query for the described behavior. I use the neo4j driver, so I have availability of using parameters.



NOTE: I and II will later be used as variables to assign unique relationships values, that's why I haven't used a single MATCH for the :Person nodes.



Also, the IN of the relationshiptype in the WHERE clause is used because of the possibility of different types of relationships to be created (and thus the old ones of that type deleted).



At last, I already have looked into UNWIND and FOREACH but can't seem to fit these into the described usecase.







neo4j cypher






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 21 '18 at 21:05







Sven Westerlaken

















asked Nov 21 '18 at 21:00









Sven WesterlakenSven Westerlaken

227




227












  • For this use case, it looks like you should probably use a Neo4j javascript Object Graph Mapper (OGM). Also, do you have the APOC plugin? And to clarify, are you simply trying to remap relationships to end at a different node?
    – Tezra
    Nov 21 '18 at 21:08










  • Well that (The OGM) is actually what I'm trying to create sort of. For the APOC, I don't really want people that use the library to be dependent on APOC as goes for an external OGM. Last part, yes kind of, but I want to combine the create clause with the ones that will create relationships with properties. That's why I thought the best option would be do delete all old relationships and create new ones.
    – Sven Westerlaken
    Nov 23 '18 at 6:28


















  • For this use case, it looks like you should probably use a Neo4j javascript Object Graph Mapper (OGM). Also, do you have the APOC plugin? And to clarify, are you simply trying to remap relationships to end at a different node?
    – Tezra
    Nov 21 '18 at 21:08










  • Well that (The OGM) is actually what I'm trying to create sort of. For the APOC, I don't really want people that use the library to be dependent on APOC as goes for an external OGM. Last part, yes kind of, but I want to combine the create clause with the ones that will create relationships with properties. That's why I thought the best option would be do delete all old relationships and create new ones.
    – Sven Westerlaken
    Nov 23 '18 at 6:28
















For this use case, it looks like you should probably use a Neo4j javascript Object Graph Mapper (OGM). Also, do you have the APOC plugin? And to clarify, are you simply trying to remap relationships to end at a different node?
– Tezra
Nov 21 '18 at 21:08




For this use case, it looks like you should probably use a Neo4j javascript Object Graph Mapper (OGM). Also, do you have the APOC plugin? And to clarify, are you simply trying to remap relationships to end at a different node?
– Tezra
Nov 21 '18 at 21:08












Well that (The OGM) is actually what I'm trying to create sort of. For the APOC, I don't really want people that use the library to be dependent on APOC as goes for an external OGM. Last part, yes kind of, but I want to combine the create clause with the ones that will create relationships with properties. That's why I thought the best option would be do delete all old relationships and create new ones.
– Sven Westerlaken
Nov 23 '18 at 6:28




Well that (The OGM) is actually what I'm trying to create sort of. For the APOC, I don't really want people that use the library to be dependent on APOC as goes for an external OGM. Last part, yes kind of, but I want to combine the create clause with the ones that will create relationships with properties. That's why I thought the best option would be do delete all old relationships and create new ones.
– Sven Westerlaken
Nov 23 '18 at 6:28












1 Answer
1






active

oldest

votes


















2














The problem with your cypher, is that each operation is performed per row



So here



MATCH (doc:Class {m_id: '5bf5b9df11c344021de89395'}), // 1
(I:Person {m_id: '5bf5b9df11c344021de89393'}), // 1
(II:Person {m_id: '5bf5b9df11c344021de89394'}), // 1
(:Class {m_id: '5bf5b9df11c344021de89395'})-[r]->() // 2
// 1 match * 1 match * 1 match * 2 match = 2 rows
WHERE type(r) IN ["HAS_STUDENT"]
CREATE (doc)-[:HAS_STUDENT]->(I), (doc)-[:HAS_STUDENT]->(II)
// 2 create * 2 rows = 4 new relations
DELETE r;


So you need to cut out the "duplicate" rows using DISTINCT before you do your create



MATCH (doc:Class {m_id: '5bf5b9df11c344021de89395'}), 
(:Class {m_id: '5bf5b9df11c344021de89395'})-[r]->()
WHERE type(r) IN ["HAS_STUDENT"]
DELETE r;
WITH DISTINCT doc
MATCH (I:Person {m_id: '5bf5b9df11c344021de89393'}),
(II:Person {m_id: '5bf5b9df11c344021de89394'})
CREATE (doc)-[:HAS_STUDENT]->(I), (doc)-[:HAS_STUDENT]->(II)





share|improve this answer





















    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53420408%2fcreate-multiple-unique-relationships-neo4j-single-query%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    2














    The problem with your cypher, is that each operation is performed per row



    So here



    MATCH (doc:Class {m_id: '5bf5b9df11c344021de89395'}), // 1
    (I:Person {m_id: '5bf5b9df11c344021de89393'}), // 1
    (II:Person {m_id: '5bf5b9df11c344021de89394'}), // 1
    (:Class {m_id: '5bf5b9df11c344021de89395'})-[r]->() // 2
    // 1 match * 1 match * 1 match * 2 match = 2 rows
    WHERE type(r) IN ["HAS_STUDENT"]
    CREATE (doc)-[:HAS_STUDENT]->(I), (doc)-[:HAS_STUDENT]->(II)
    // 2 create * 2 rows = 4 new relations
    DELETE r;


    So you need to cut out the "duplicate" rows using DISTINCT before you do your create



    MATCH (doc:Class {m_id: '5bf5b9df11c344021de89395'}), 
    (:Class {m_id: '5bf5b9df11c344021de89395'})-[r]->()
    WHERE type(r) IN ["HAS_STUDENT"]
    DELETE r;
    WITH DISTINCT doc
    MATCH (I:Person {m_id: '5bf5b9df11c344021de89393'}),
    (II:Person {m_id: '5bf5b9df11c344021de89394'})
    CREATE (doc)-[:HAS_STUDENT]->(I), (doc)-[:HAS_STUDENT]->(II)





    share|improve this answer


























      2














      The problem with your cypher, is that each operation is performed per row



      So here



      MATCH (doc:Class {m_id: '5bf5b9df11c344021de89395'}), // 1
      (I:Person {m_id: '5bf5b9df11c344021de89393'}), // 1
      (II:Person {m_id: '5bf5b9df11c344021de89394'}), // 1
      (:Class {m_id: '5bf5b9df11c344021de89395'})-[r]->() // 2
      // 1 match * 1 match * 1 match * 2 match = 2 rows
      WHERE type(r) IN ["HAS_STUDENT"]
      CREATE (doc)-[:HAS_STUDENT]->(I), (doc)-[:HAS_STUDENT]->(II)
      // 2 create * 2 rows = 4 new relations
      DELETE r;


      So you need to cut out the "duplicate" rows using DISTINCT before you do your create



      MATCH (doc:Class {m_id: '5bf5b9df11c344021de89395'}), 
      (:Class {m_id: '5bf5b9df11c344021de89395'})-[r]->()
      WHERE type(r) IN ["HAS_STUDENT"]
      DELETE r;
      WITH DISTINCT doc
      MATCH (I:Person {m_id: '5bf5b9df11c344021de89393'}),
      (II:Person {m_id: '5bf5b9df11c344021de89394'})
      CREATE (doc)-[:HAS_STUDENT]->(I), (doc)-[:HAS_STUDENT]->(II)





      share|improve this answer
























        2












        2








        2






        The problem with your cypher, is that each operation is performed per row



        So here



        MATCH (doc:Class {m_id: '5bf5b9df11c344021de89395'}), // 1
        (I:Person {m_id: '5bf5b9df11c344021de89393'}), // 1
        (II:Person {m_id: '5bf5b9df11c344021de89394'}), // 1
        (:Class {m_id: '5bf5b9df11c344021de89395'})-[r]->() // 2
        // 1 match * 1 match * 1 match * 2 match = 2 rows
        WHERE type(r) IN ["HAS_STUDENT"]
        CREATE (doc)-[:HAS_STUDENT]->(I), (doc)-[:HAS_STUDENT]->(II)
        // 2 create * 2 rows = 4 new relations
        DELETE r;


        So you need to cut out the "duplicate" rows using DISTINCT before you do your create



        MATCH (doc:Class {m_id: '5bf5b9df11c344021de89395'}), 
        (:Class {m_id: '5bf5b9df11c344021de89395'})-[r]->()
        WHERE type(r) IN ["HAS_STUDENT"]
        DELETE r;
        WITH DISTINCT doc
        MATCH (I:Person {m_id: '5bf5b9df11c344021de89393'}),
        (II:Person {m_id: '5bf5b9df11c344021de89394'})
        CREATE (doc)-[:HAS_STUDENT]->(I), (doc)-[:HAS_STUDENT]->(II)





        share|improve this answer












        The problem with your cypher, is that each operation is performed per row



        So here



        MATCH (doc:Class {m_id: '5bf5b9df11c344021de89395'}), // 1
        (I:Person {m_id: '5bf5b9df11c344021de89393'}), // 1
        (II:Person {m_id: '5bf5b9df11c344021de89394'}), // 1
        (:Class {m_id: '5bf5b9df11c344021de89395'})-[r]->() // 2
        // 1 match * 1 match * 1 match * 2 match = 2 rows
        WHERE type(r) IN ["HAS_STUDENT"]
        CREATE (doc)-[:HAS_STUDENT]->(I), (doc)-[:HAS_STUDENT]->(II)
        // 2 create * 2 rows = 4 new relations
        DELETE r;


        So you need to cut out the "duplicate" rows using DISTINCT before you do your create



        MATCH (doc:Class {m_id: '5bf5b9df11c344021de89395'}), 
        (:Class {m_id: '5bf5b9df11c344021de89395'})-[r]->()
        WHERE type(r) IN ["HAS_STUDENT"]
        DELETE r;
        WITH DISTINCT doc
        MATCH (I:Person {m_id: '5bf5b9df11c344021de89393'}),
        (II:Person {m_id: '5bf5b9df11c344021de89394'})
        CREATE (doc)-[:HAS_STUDENT]->(I), (doc)-[:HAS_STUDENT]->(II)






        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 21 '18 at 21:13









        TezraTezra

        5,03621042




        5,03621042






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.





            Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


            Please pay close attention to the following guidance:


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53420408%2fcreate-multiple-unique-relationships-neo4j-single-query%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            404 Error Contact Form 7 ajax form submitting

            How to know if a Active Directory user can login interactively

            Refactoring coordinates for Minecraft Pi buildings written in Python