Create multiple unique relationships neo4j (single query)
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
add a comment |
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
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
add a comment |
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
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
neo4j cypher
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
add a comment |
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
add a comment |
1 Answer
1
active
oldest
votes
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)
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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)
add a comment |
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)
add a comment |
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)
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)
answered Nov 21 '18 at 21:13
TezraTezra
5,03621042
5,03621042
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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