perform additional match if the return node has a certain type
I've got a model that looks like this
I want to for a player to recommend a quest that would allow to complete his set of armor. I am doing this cypher
query to return relationship quest -> boots
.
MATCH (w:Armor)<-[:WEARS]-(p:Player)
MATCH (w)-[:PART_OF]->(set:ArmorSet)
MATCH (missing)-[:PART_OF]->(set)
MATCH (missing)<--(anything)
WHERE NOT (p)-[:WEARS]->(missing)
RETURN missing, anything
But how to adjust this query to return the NPC
that gives the quest if boots
is the reward of the quest? Basically I want to check that if the node is of quest
type, then I should return npc
that gives that quest.
How to achieve that in Neo4j?
neo4j cypher
add a comment |
I've got a model that looks like this
I want to for a player to recommend a quest that would allow to complete his set of armor. I am doing this cypher
query to return relationship quest -> boots
.
MATCH (w:Armor)<-[:WEARS]-(p:Player)
MATCH (w)-[:PART_OF]->(set:ArmorSet)
MATCH (missing)-[:PART_OF]->(set)
MATCH (missing)<--(anything)
WHERE NOT (p)-[:WEARS]->(missing)
RETURN missing, anything
But how to adjust this query to return the NPC
that gives the quest if boots
is the reward of the quest? Basically I want to check that if the node is of quest
type, then I should return npc
that gives that quest.
How to achieve that in Neo4j?
neo4j cypher
add a comment |
I've got a model that looks like this
I want to for a player to recommend a quest that would allow to complete his set of armor. I am doing this cypher
query to return relationship quest -> boots
.
MATCH (w:Armor)<-[:WEARS]-(p:Player)
MATCH (w)-[:PART_OF]->(set:ArmorSet)
MATCH (missing)-[:PART_OF]->(set)
MATCH (missing)<--(anything)
WHERE NOT (p)-[:WEARS]->(missing)
RETURN missing, anything
But how to adjust this query to return the NPC
that gives the quest if boots
is the reward of the quest? Basically I want to check that if the node is of quest
type, then I should return npc
that gives that quest.
How to achieve that in Neo4j?
neo4j cypher
I've got a model that looks like this
I want to for a player to recommend a quest that would allow to complete his set of armor. I am doing this cypher
query to return relationship quest -> boots
.
MATCH (w:Armor)<-[:WEARS]-(p:Player)
MATCH (w)-[:PART_OF]->(set:ArmorSet)
MATCH (missing)-[:PART_OF]->(set)
MATCH (missing)<--(anything)
WHERE NOT (p)-[:WEARS]->(missing)
RETURN missing, anything
But how to adjust this query to return the NPC
that gives the quest if boots
is the reward of the quest? Basically I want to check that if the node is of quest
type, then I should return npc
that gives that quest.
How to achieve that in Neo4j?
neo4j cypher
neo4j cypher
edited Nov 20 '18 at 4:38
ThirstForKnowledge
6651112
6651112
asked Nov 19 '18 at 18:05
lapotslapots
3,7221360133
3,7221360133
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
Original answer
Creating your graph
For the ease of possible further answers and solutions I note my graph creating statement:
CREATE
(player:Player {name: 'Player'}),
(shield:Armor {name: 'Shield'}),
(armor:Armor {name: 'Armor'}),
(gauntlets:Armor {name: 'Gauntlets'}),
(boots:Armor {name: 'Boots'}),
(helmet:Armor {name: 'Helmet'}),
(dragonSet:ArmorSet {name: 'Dragon Set'}),
(quest1:Quest {name: 'Quest I'}),
(quest2:Quest {name: 'Quest II'}),
(npc1:Npc {name: 'NPC I'}),
(npc2:Npc {name: 'NPC II'}),
(player)-[:WEARS]->(shield)-[:PART_OF]->(dragonSet),
(player)-[:WEARS]->(armor)-[:PART_OF]->(dragonSet),
(player)-[:WEARS]->(gauntlets)-[:PART_OF]->(dragonSet),
(npc1)-[:PROVIDES]->(quest1)-[:REWARDS]->(boots)-[:PART_OF]->(dragonSet),
(npc2)-[:PROVIDES]->(quest2)-[:REWARDS]->(helmet)-[:PART_OF]->(dragonSet);
Line 2 to 12 creates the nodes, whereas line 13 to 17 establishes the relationships between them.
Solution
MATCH
(player:Player)-[:WEARS]->(armor:Armor)-[:PART_OF]->(dragonSet:ArmorSet),
(missing)-[:PART_OF]->(dragonSet)
WHERE NOT (player)-[:WEARS]->(missing:Armor)
WITH DISTINCT missing
MATCH (npc:Npc)-[:PROVIDES]->(quest:Quest)-[:REWARDS]->(missing)
RETURN npc.name AS npcName, quest.name AS questName, missing.name AS missingArmorName;
Explanation
- Line 2 defines the pattern "A
Player
wears anArmor
, which is part of anArmorSet
". - Line 3 introduces the variable
missing
that is necessary for the exclusion "Player
wears a missingArmor
" in line 4
"The WITH clause allows query parts to be chained together, piping the results from one to be used as starting points or criteria in the next." (Taken from Neo4j developers manual, WITH clauses chapter)
- Line 6 for the identified missing
Armor
s retrieve theQuest
providingNpc
s - Line 7 render the desired output
Result
╒═════════╤═══════════╤══════════════════╕
│"npcName"│"questName"│"missingArmorName"│
╞═════════╪═══════════╪══════════════════╡
│"NPC II" │"Quest II" │"Helmet" │
├─────────┼───────────┼──────────────────┤
│"NPC I" │"Quest I" │"Boots" │
└─────────┴───────────┴──────────────────┘
Extension regarding your comment
If it is important to identify Armor
s that can be retrieved by Quest
s only, we have to enhance your model by a label Monster
with an according relationship RANDOM_DROPS
.
Creating your graph
CREATE
(player:Player {name: 'Player'}),
(shield:Armor {name: 'Shield'}),
(armor:Armor {name: 'Armor'}),
(gauntlets:Armor {name: 'Gauntlets'}),
(boots:Armor {name: 'Boots'}),
(helmet:Armor {name: 'Helmet'}),
(dragonSet:ArmorSet {name: 'Dragon Set'}),
(quest1:Quest {name: 'Quest I'}),
(quest2:Quest {name: 'Quest II'}),
(npc1:Npc {name: 'NPC I'}),
(npc2:Npc {name: 'NPC II'}),
(monster1:Monster {name: 'Monster I'}),
(monster2:Monster {name: 'Monster II'}),
(player)-[:WEARS]->(shield)-[:PART_OF]->(dragonSet),
(player)-[:WEARS]->(armor)-[:PART_OF]->(dragonSet),
(player)-[:WEARS]->(gauntlets)-[:PART_OF]->(dragonSet),
(npc1)-[:PROVIDES]->(quest1)-[:REWARDS]->(boots)-[:PART_OF]->(dragonSet),
(npc2)-[:PROVIDES]->(quest2)-[:REWARDS]->(helmet)-[:PART_OF]->(dragonSet),
(monster2)-[:RANDOM_DROPS]->(boots),
(monster1)-[:RANDOM_DROPS]->(gauntlets),
(monster1)-[:RANDOM_DROPS]->(shield),
(monster1)-[:RANDOM_DROPS]->(armor);
Solution
MATCH
(player:Player)-[:WEARS]->(armor:Armor)-[:PART_OF]->(dragonSet:ArmorSet),
(missing)-[:PART_OF]->(dragonSet)
WHERE NOT (player)-[:WEARS]->(missing:Armor)
WITH DISTINCT missing
MATCH (npc:Npc)-[:PROVIDES]->(quest:Quest)-[:REWARDS]->(missing)
WHERE NOT (:Monster)-[:RANDOM_DROPS]->(missing)
RETURN npc.name AS npcName, quest.name AS questName, missing.name AS missingArmorName;
Result
╒═════════╤═══════════╤══════════════════╕
│"npcName"│"questName"│"missingArmorName"│
╞═════════╪═══════════╪══════════════════╡
│"NPC II" │"Quest II" │"Helmet" │
└─────────┴───────────┴──────────────────┘
The problem is that in this case I am not sure that theboots
orhelmet
can be only received as the rewards of quest. They might as well be a random drop from some mob. Or I have just tomatch
all possible cases in the query?
– lapots
Nov 20 '18 at 7:20
I’ve extended my answer to reflect your "quest only" requirement. Does the answer solve your challenge?
– ThirstForKnowledge
Nov 20 '18 at 10:37
I kinda get it now. So basically you assume that every quest will definitely have some relation to NPC (in that case) and if there is a quest than you return it. I thought it is possible to infer the relation to NPC by knowing thatquest
node exist. But I don't think in graphs so I am not sure if I should the logic use such logic for graph databases.
– lapots
Nov 20 '18 at 12:12
Yes, that's what I went for. If my assumption doesn’t harmonize with your concrete scenario, you could split the lastMATCH
clause in an obligatory part that identifies theQuest
and an optional part which finds the relatedNpc
, if there is one. Just now I have no Neo4j instance at hand unfortunately to verify the Cypher statement, but I think about something like this:MATCH (npc:Npc)-[:PROVIDES]->(quest:Quest), OPTIONAL MATCH (quest)-[:REWARDS]->(missing)
.
– ThirstForKnowledge
Nov 20 '18 at 12:42
In my case it is probablyoptional
match for quests andoptional
for npc.
– lapots
Nov 20 '18 at 13:25
add a comment |
The coalesce function in Neo4j can be used to compress multiple variables to use the most relevant, non-null value.
MATCH (w:Armor)<-[:WEARS]-(p:Player)
MATCH (w)-[:PART_OF]->(set:ArmorSet)
MATCH (missing)-[:PART_OF]->(set)
MATCH (missing)<--(anything)
WHERE NOT (p)-[:WEARS]->(missing)
OPTIONAL MATCH (anything)<-[:GIVES]-(source)
RETURN missing, coalesce(source, anything) as source
So in this example, coalesce will return the value of source if their is one, otherwise it will move to the next one and repeat. If all values are null, it will return null.
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%2f53380333%2fperform-additional-match-if-the-return-node-has-a-certain-type%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
Original answer
Creating your graph
For the ease of possible further answers and solutions I note my graph creating statement:
CREATE
(player:Player {name: 'Player'}),
(shield:Armor {name: 'Shield'}),
(armor:Armor {name: 'Armor'}),
(gauntlets:Armor {name: 'Gauntlets'}),
(boots:Armor {name: 'Boots'}),
(helmet:Armor {name: 'Helmet'}),
(dragonSet:ArmorSet {name: 'Dragon Set'}),
(quest1:Quest {name: 'Quest I'}),
(quest2:Quest {name: 'Quest II'}),
(npc1:Npc {name: 'NPC I'}),
(npc2:Npc {name: 'NPC II'}),
(player)-[:WEARS]->(shield)-[:PART_OF]->(dragonSet),
(player)-[:WEARS]->(armor)-[:PART_OF]->(dragonSet),
(player)-[:WEARS]->(gauntlets)-[:PART_OF]->(dragonSet),
(npc1)-[:PROVIDES]->(quest1)-[:REWARDS]->(boots)-[:PART_OF]->(dragonSet),
(npc2)-[:PROVIDES]->(quest2)-[:REWARDS]->(helmet)-[:PART_OF]->(dragonSet);
Line 2 to 12 creates the nodes, whereas line 13 to 17 establishes the relationships between them.
Solution
MATCH
(player:Player)-[:WEARS]->(armor:Armor)-[:PART_OF]->(dragonSet:ArmorSet),
(missing)-[:PART_OF]->(dragonSet)
WHERE NOT (player)-[:WEARS]->(missing:Armor)
WITH DISTINCT missing
MATCH (npc:Npc)-[:PROVIDES]->(quest:Quest)-[:REWARDS]->(missing)
RETURN npc.name AS npcName, quest.name AS questName, missing.name AS missingArmorName;
Explanation
- Line 2 defines the pattern "A
Player
wears anArmor
, which is part of anArmorSet
". - Line 3 introduces the variable
missing
that is necessary for the exclusion "Player
wears a missingArmor
" in line 4
"The WITH clause allows query parts to be chained together, piping the results from one to be used as starting points or criteria in the next." (Taken from Neo4j developers manual, WITH clauses chapter)
- Line 6 for the identified missing
Armor
s retrieve theQuest
providingNpc
s - Line 7 render the desired output
Result
╒═════════╤═══════════╤══════════════════╕
│"npcName"│"questName"│"missingArmorName"│
╞═════════╪═══════════╪══════════════════╡
│"NPC II" │"Quest II" │"Helmet" │
├─────────┼───────────┼──────────────────┤
│"NPC I" │"Quest I" │"Boots" │
└─────────┴───────────┴──────────────────┘
Extension regarding your comment
If it is important to identify Armor
s that can be retrieved by Quest
s only, we have to enhance your model by a label Monster
with an according relationship RANDOM_DROPS
.
Creating your graph
CREATE
(player:Player {name: 'Player'}),
(shield:Armor {name: 'Shield'}),
(armor:Armor {name: 'Armor'}),
(gauntlets:Armor {name: 'Gauntlets'}),
(boots:Armor {name: 'Boots'}),
(helmet:Armor {name: 'Helmet'}),
(dragonSet:ArmorSet {name: 'Dragon Set'}),
(quest1:Quest {name: 'Quest I'}),
(quest2:Quest {name: 'Quest II'}),
(npc1:Npc {name: 'NPC I'}),
(npc2:Npc {name: 'NPC II'}),
(monster1:Monster {name: 'Monster I'}),
(monster2:Monster {name: 'Monster II'}),
(player)-[:WEARS]->(shield)-[:PART_OF]->(dragonSet),
(player)-[:WEARS]->(armor)-[:PART_OF]->(dragonSet),
(player)-[:WEARS]->(gauntlets)-[:PART_OF]->(dragonSet),
(npc1)-[:PROVIDES]->(quest1)-[:REWARDS]->(boots)-[:PART_OF]->(dragonSet),
(npc2)-[:PROVIDES]->(quest2)-[:REWARDS]->(helmet)-[:PART_OF]->(dragonSet),
(monster2)-[:RANDOM_DROPS]->(boots),
(monster1)-[:RANDOM_DROPS]->(gauntlets),
(monster1)-[:RANDOM_DROPS]->(shield),
(monster1)-[:RANDOM_DROPS]->(armor);
Solution
MATCH
(player:Player)-[:WEARS]->(armor:Armor)-[:PART_OF]->(dragonSet:ArmorSet),
(missing)-[:PART_OF]->(dragonSet)
WHERE NOT (player)-[:WEARS]->(missing:Armor)
WITH DISTINCT missing
MATCH (npc:Npc)-[:PROVIDES]->(quest:Quest)-[:REWARDS]->(missing)
WHERE NOT (:Monster)-[:RANDOM_DROPS]->(missing)
RETURN npc.name AS npcName, quest.name AS questName, missing.name AS missingArmorName;
Result
╒═════════╤═══════════╤══════════════════╕
│"npcName"│"questName"│"missingArmorName"│
╞═════════╪═══════════╪══════════════════╡
│"NPC II" │"Quest II" │"Helmet" │
└─────────┴───────────┴──────────────────┘
The problem is that in this case I am not sure that theboots
orhelmet
can be only received as the rewards of quest. They might as well be a random drop from some mob. Or I have just tomatch
all possible cases in the query?
– lapots
Nov 20 '18 at 7:20
I’ve extended my answer to reflect your "quest only" requirement. Does the answer solve your challenge?
– ThirstForKnowledge
Nov 20 '18 at 10:37
I kinda get it now. So basically you assume that every quest will definitely have some relation to NPC (in that case) and if there is a quest than you return it. I thought it is possible to infer the relation to NPC by knowing thatquest
node exist. But I don't think in graphs so I am not sure if I should the logic use such logic for graph databases.
– lapots
Nov 20 '18 at 12:12
Yes, that's what I went for. If my assumption doesn’t harmonize with your concrete scenario, you could split the lastMATCH
clause in an obligatory part that identifies theQuest
and an optional part which finds the relatedNpc
, if there is one. Just now I have no Neo4j instance at hand unfortunately to verify the Cypher statement, but I think about something like this:MATCH (npc:Npc)-[:PROVIDES]->(quest:Quest), OPTIONAL MATCH (quest)-[:REWARDS]->(missing)
.
– ThirstForKnowledge
Nov 20 '18 at 12:42
In my case it is probablyoptional
match for quests andoptional
for npc.
– lapots
Nov 20 '18 at 13:25
add a comment |
Original answer
Creating your graph
For the ease of possible further answers and solutions I note my graph creating statement:
CREATE
(player:Player {name: 'Player'}),
(shield:Armor {name: 'Shield'}),
(armor:Armor {name: 'Armor'}),
(gauntlets:Armor {name: 'Gauntlets'}),
(boots:Armor {name: 'Boots'}),
(helmet:Armor {name: 'Helmet'}),
(dragonSet:ArmorSet {name: 'Dragon Set'}),
(quest1:Quest {name: 'Quest I'}),
(quest2:Quest {name: 'Quest II'}),
(npc1:Npc {name: 'NPC I'}),
(npc2:Npc {name: 'NPC II'}),
(player)-[:WEARS]->(shield)-[:PART_OF]->(dragonSet),
(player)-[:WEARS]->(armor)-[:PART_OF]->(dragonSet),
(player)-[:WEARS]->(gauntlets)-[:PART_OF]->(dragonSet),
(npc1)-[:PROVIDES]->(quest1)-[:REWARDS]->(boots)-[:PART_OF]->(dragonSet),
(npc2)-[:PROVIDES]->(quest2)-[:REWARDS]->(helmet)-[:PART_OF]->(dragonSet);
Line 2 to 12 creates the nodes, whereas line 13 to 17 establishes the relationships between them.
Solution
MATCH
(player:Player)-[:WEARS]->(armor:Armor)-[:PART_OF]->(dragonSet:ArmorSet),
(missing)-[:PART_OF]->(dragonSet)
WHERE NOT (player)-[:WEARS]->(missing:Armor)
WITH DISTINCT missing
MATCH (npc:Npc)-[:PROVIDES]->(quest:Quest)-[:REWARDS]->(missing)
RETURN npc.name AS npcName, quest.name AS questName, missing.name AS missingArmorName;
Explanation
- Line 2 defines the pattern "A
Player
wears anArmor
, which is part of anArmorSet
". - Line 3 introduces the variable
missing
that is necessary for the exclusion "Player
wears a missingArmor
" in line 4
"The WITH clause allows query parts to be chained together, piping the results from one to be used as starting points or criteria in the next." (Taken from Neo4j developers manual, WITH clauses chapter)
- Line 6 for the identified missing
Armor
s retrieve theQuest
providingNpc
s - Line 7 render the desired output
Result
╒═════════╤═══════════╤══════════════════╕
│"npcName"│"questName"│"missingArmorName"│
╞═════════╪═══════════╪══════════════════╡
│"NPC II" │"Quest II" │"Helmet" │
├─────────┼───────────┼──────────────────┤
│"NPC I" │"Quest I" │"Boots" │
└─────────┴───────────┴──────────────────┘
Extension regarding your comment
If it is important to identify Armor
s that can be retrieved by Quest
s only, we have to enhance your model by a label Monster
with an according relationship RANDOM_DROPS
.
Creating your graph
CREATE
(player:Player {name: 'Player'}),
(shield:Armor {name: 'Shield'}),
(armor:Armor {name: 'Armor'}),
(gauntlets:Armor {name: 'Gauntlets'}),
(boots:Armor {name: 'Boots'}),
(helmet:Armor {name: 'Helmet'}),
(dragonSet:ArmorSet {name: 'Dragon Set'}),
(quest1:Quest {name: 'Quest I'}),
(quest2:Quest {name: 'Quest II'}),
(npc1:Npc {name: 'NPC I'}),
(npc2:Npc {name: 'NPC II'}),
(monster1:Monster {name: 'Monster I'}),
(monster2:Monster {name: 'Monster II'}),
(player)-[:WEARS]->(shield)-[:PART_OF]->(dragonSet),
(player)-[:WEARS]->(armor)-[:PART_OF]->(dragonSet),
(player)-[:WEARS]->(gauntlets)-[:PART_OF]->(dragonSet),
(npc1)-[:PROVIDES]->(quest1)-[:REWARDS]->(boots)-[:PART_OF]->(dragonSet),
(npc2)-[:PROVIDES]->(quest2)-[:REWARDS]->(helmet)-[:PART_OF]->(dragonSet),
(monster2)-[:RANDOM_DROPS]->(boots),
(monster1)-[:RANDOM_DROPS]->(gauntlets),
(monster1)-[:RANDOM_DROPS]->(shield),
(monster1)-[:RANDOM_DROPS]->(armor);
Solution
MATCH
(player:Player)-[:WEARS]->(armor:Armor)-[:PART_OF]->(dragonSet:ArmorSet),
(missing)-[:PART_OF]->(dragonSet)
WHERE NOT (player)-[:WEARS]->(missing:Armor)
WITH DISTINCT missing
MATCH (npc:Npc)-[:PROVIDES]->(quest:Quest)-[:REWARDS]->(missing)
WHERE NOT (:Monster)-[:RANDOM_DROPS]->(missing)
RETURN npc.name AS npcName, quest.name AS questName, missing.name AS missingArmorName;
Result
╒═════════╤═══════════╤══════════════════╕
│"npcName"│"questName"│"missingArmorName"│
╞═════════╪═══════════╪══════════════════╡
│"NPC II" │"Quest II" │"Helmet" │
└─────────┴───────────┴──────────────────┘
The problem is that in this case I am not sure that theboots
orhelmet
can be only received as the rewards of quest. They might as well be a random drop from some mob. Or I have just tomatch
all possible cases in the query?
– lapots
Nov 20 '18 at 7:20
I’ve extended my answer to reflect your "quest only" requirement. Does the answer solve your challenge?
– ThirstForKnowledge
Nov 20 '18 at 10:37
I kinda get it now. So basically you assume that every quest will definitely have some relation to NPC (in that case) and if there is a quest than you return it. I thought it is possible to infer the relation to NPC by knowing thatquest
node exist. But I don't think in graphs so I am not sure if I should the logic use such logic for graph databases.
– lapots
Nov 20 '18 at 12:12
Yes, that's what I went for. If my assumption doesn’t harmonize with your concrete scenario, you could split the lastMATCH
clause in an obligatory part that identifies theQuest
and an optional part which finds the relatedNpc
, if there is one. Just now I have no Neo4j instance at hand unfortunately to verify the Cypher statement, but I think about something like this:MATCH (npc:Npc)-[:PROVIDES]->(quest:Quest), OPTIONAL MATCH (quest)-[:REWARDS]->(missing)
.
– ThirstForKnowledge
Nov 20 '18 at 12:42
In my case it is probablyoptional
match for quests andoptional
for npc.
– lapots
Nov 20 '18 at 13:25
add a comment |
Original answer
Creating your graph
For the ease of possible further answers and solutions I note my graph creating statement:
CREATE
(player:Player {name: 'Player'}),
(shield:Armor {name: 'Shield'}),
(armor:Armor {name: 'Armor'}),
(gauntlets:Armor {name: 'Gauntlets'}),
(boots:Armor {name: 'Boots'}),
(helmet:Armor {name: 'Helmet'}),
(dragonSet:ArmorSet {name: 'Dragon Set'}),
(quest1:Quest {name: 'Quest I'}),
(quest2:Quest {name: 'Quest II'}),
(npc1:Npc {name: 'NPC I'}),
(npc2:Npc {name: 'NPC II'}),
(player)-[:WEARS]->(shield)-[:PART_OF]->(dragonSet),
(player)-[:WEARS]->(armor)-[:PART_OF]->(dragonSet),
(player)-[:WEARS]->(gauntlets)-[:PART_OF]->(dragonSet),
(npc1)-[:PROVIDES]->(quest1)-[:REWARDS]->(boots)-[:PART_OF]->(dragonSet),
(npc2)-[:PROVIDES]->(quest2)-[:REWARDS]->(helmet)-[:PART_OF]->(dragonSet);
Line 2 to 12 creates the nodes, whereas line 13 to 17 establishes the relationships between them.
Solution
MATCH
(player:Player)-[:WEARS]->(armor:Armor)-[:PART_OF]->(dragonSet:ArmorSet),
(missing)-[:PART_OF]->(dragonSet)
WHERE NOT (player)-[:WEARS]->(missing:Armor)
WITH DISTINCT missing
MATCH (npc:Npc)-[:PROVIDES]->(quest:Quest)-[:REWARDS]->(missing)
RETURN npc.name AS npcName, quest.name AS questName, missing.name AS missingArmorName;
Explanation
- Line 2 defines the pattern "A
Player
wears anArmor
, which is part of anArmorSet
". - Line 3 introduces the variable
missing
that is necessary for the exclusion "Player
wears a missingArmor
" in line 4
"The WITH clause allows query parts to be chained together, piping the results from one to be used as starting points or criteria in the next." (Taken from Neo4j developers manual, WITH clauses chapter)
- Line 6 for the identified missing
Armor
s retrieve theQuest
providingNpc
s - Line 7 render the desired output
Result
╒═════════╤═══════════╤══════════════════╕
│"npcName"│"questName"│"missingArmorName"│
╞═════════╪═══════════╪══════════════════╡
│"NPC II" │"Quest II" │"Helmet" │
├─────────┼───────────┼──────────────────┤
│"NPC I" │"Quest I" │"Boots" │
└─────────┴───────────┴──────────────────┘
Extension regarding your comment
If it is important to identify Armor
s that can be retrieved by Quest
s only, we have to enhance your model by a label Monster
with an according relationship RANDOM_DROPS
.
Creating your graph
CREATE
(player:Player {name: 'Player'}),
(shield:Armor {name: 'Shield'}),
(armor:Armor {name: 'Armor'}),
(gauntlets:Armor {name: 'Gauntlets'}),
(boots:Armor {name: 'Boots'}),
(helmet:Armor {name: 'Helmet'}),
(dragonSet:ArmorSet {name: 'Dragon Set'}),
(quest1:Quest {name: 'Quest I'}),
(quest2:Quest {name: 'Quest II'}),
(npc1:Npc {name: 'NPC I'}),
(npc2:Npc {name: 'NPC II'}),
(monster1:Monster {name: 'Monster I'}),
(monster2:Monster {name: 'Monster II'}),
(player)-[:WEARS]->(shield)-[:PART_OF]->(dragonSet),
(player)-[:WEARS]->(armor)-[:PART_OF]->(dragonSet),
(player)-[:WEARS]->(gauntlets)-[:PART_OF]->(dragonSet),
(npc1)-[:PROVIDES]->(quest1)-[:REWARDS]->(boots)-[:PART_OF]->(dragonSet),
(npc2)-[:PROVIDES]->(quest2)-[:REWARDS]->(helmet)-[:PART_OF]->(dragonSet),
(monster2)-[:RANDOM_DROPS]->(boots),
(monster1)-[:RANDOM_DROPS]->(gauntlets),
(monster1)-[:RANDOM_DROPS]->(shield),
(monster1)-[:RANDOM_DROPS]->(armor);
Solution
MATCH
(player:Player)-[:WEARS]->(armor:Armor)-[:PART_OF]->(dragonSet:ArmorSet),
(missing)-[:PART_OF]->(dragonSet)
WHERE NOT (player)-[:WEARS]->(missing:Armor)
WITH DISTINCT missing
MATCH (npc:Npc)-[:PROVIDES]->(quest:Quest)-[:REWARDS]->(missing)
WHERE NOT (:Monster)-[:RANDOM_DROPS]->(missing)
RETURN npc.name AS npcName, quest.name AS questName, missing.name AS missingArmorName;
Result
╒═════════╤═══════════╤══════════════════╕
│"npcName"│"questName"│"missingArmorName"│
╞═════════╪═══════════╪══════════════════╡
│"NPC II" │"Quest II" │"Helmet" │
└─────────┴───────────┴──────────────────┘
Original answer
Creating your graph
For the ease of possible further answers and solutions I note my graph creating statement:
CREATE
(player:Player {name: 'Player'}),
(shield:Armor {name: 'Shield'}),
(armor:Armor {name: 'Armor'}),
(gauntlets:Armor {name: 'Gauntlets'}),
(boots:Armor {name: 'Boots'}),
(helmet:Armor {name: 'Helmet'}),
(dragonSet:ArmorSet {name: 'Dragon Set'}),
(quest1:Quest {name: 'Quest I'}),
(quest2:Quest {name: 'Quest II'}),
(npc1:Npc {name: 'NPC I'}),
(npc2:Npc {name: 'NPC II'}),
(player)-[:WEARS]->(shield)-[:PART_OF]->(dragonSet),
(player)-[:WEARS]->(armor)-[:PART_OF]->(dragonSet),
(player)-[:WEARS]->(gauntlets)-[:PART_OF]->(dragonSet),
(npc1)-[:PROVIDES]->(quest1)-[:REWARDS]->(boots)-[:PART_OF]->(dragonSet),
(npc2)-[:PROVIDES]->(quest2)-[:REWARDS]->(helmet)-[:PART_OF]->(dragonSet);
Line 2 to 12 creates the nodes, whereas line 13 to 17 establishes the relationships between them.
Solution
MATCH
(player:Player)-[:WEARS]->(armor:Armor)-[:PART_OF]->(dragonSet:ArmorSet),
(missing)-[:PART_OF]->(dragonSet)
WHERE NOT (player)-[:WEARS]->(missing:Armor)
WITH DISTINCT missing
MATCH (npc:Npc)-[:PROVIDES]->(quest:Quest)-[:REWARDS]->(missing)
RETURN npc.name AS npcName, quest.name AS questName, missing.name AS missingArmorName;
Explanation
- Line 2 defines the pattern "A
Player
wears anArmor
, which is part of anArmorSet
". - Line 3 introduces the variable
missing
that is necessary for the exclusion "Player
wears a missingArmor
" in line 4
"The WITH clause allows query parts to be chained together, piping the results from one to be used as starting points or criteria in the next." (Taken from Neo4j developers manual, WITH clauses chapter)
- Line 6 for the identified missing
Armor
s retrieve theQuest
providingNpc
s - Line 7 render the desired output
Result
╒═════════╤═══════════╤══════════════════╕
│"npcName"│"questName"│"missingArmorName"│
╞═════════╪═══════════╪══════════════════╡
│"NPC II" │"Quest II" │"Helmet" │
├─────────┼───────────┼──────────────────┤
│"NPC I" │"Quest I" │"Boots" │
└─────────┴───────────┴──────────────────┘
Extension regarding your comment
If it is important to identify Armor
s that can be retrieved by Quest
s only, we have to enhance your model by a label Monster
with an according relationship RANDOM_DROPS
.
Creating your graph
CREATE
(player:Player {name: 'Player'}),
(shield:Armor {name: 'Shield'}),
(armor:Armor {name: 'Armor'}),
(gauntlets:Armor {name: 'Gauntlets'}),
(boots:Armor {name: 'Boots'}),
(helmet:Armor {name: 'Helmet'}),
(dragonSet:ArmorSet {name: 'Dragon Set'}),
(quest1:Quest {name: 'Quest I'}),
(quest2:Quest {name: 'Quest II'}),
(npc1:Npc {name: 'NPC I'}),
(npc2:Npc {name: 'NPC II'}),
(monster1:Monster {name: 'Monster I'}),
(monster2:Monster {name: 'Monster II'}),
(player)-[:WEARS]->(shield)-[:PART_OF]->(dragonSet),
(player)-[:WEARS]->(armor)-[:PART_OF]->(dragonSet),
(player)-[:WEARS]->(gauntlets)-[:PART_OF]->(dragonSet),
(npc1)-[:PROVIDES]->(quest1)-[:REWARDS]->(boots)-[:PART_OF]->(dragonSet),
(npc2)-[:PROVIDES]->(quest2)-[:REWARDS]->(helmet)-[:PART_OF]->(dragonSet),
(monster2)-[:RANDOM_DROPS]->(boots),
(monster1)-[:RANDOM_DROPS]->(gauntlets),
(monster1)-[:RANDOM_DROPS]->(shield),
(monster1)-[:RANDOM_DROPS]->(armor);
Solution
MATCH
(player:Player)-[:WEARS]->(armor:Armor)-[:PART_OF]->(dragonSet:ArmorSet),
(missing)-[:PART_OF]->(dragonSet)
WHERE NOT (player)-[:WEARS]->(missing:Armor)
WITH DISTINCT missing
MATCH (npc:Npc)-[:PROVIDES]->(quest:Quest)-[:REWARDS]->(missing)
WHERE NOT (:Monster)-[:RANDOM_DROPS]->(missing)
RETURN npc.name AS npcName, quest.name AS questName, missing.name AS missingArmorName;
Result
╒═════════╤═══════════╤══════════════════╕
│"npcName"│"questName"│"missingArmorName"│
╞═════════╪═══════════╪══════════════════╡
│"NPC II" │"Quest II" │"Helmet" │
└─────────┴───────────┴──────────────────┘
edited Nov 20 '18 at 10:33
answered Nov 19 '18 at 22:37
ThirstForKnowledgeThirstForKnowledge
6651112
6651112
The problem is that in this case I am not sure that theboots
orhelmet
can be only received as the rewards of quest. They might as well be a random drop from some mob. Or I have just tomatch
all possible cases in the query?
– lapots
Nov 20 '18 at 7:20
I’ve extended my answer to reflect your "quest only" requirement. Does the answer solve your challenge?
– ThirstForKnowledge
Nov 20 '18 at 10:37
I kinda get it now. So basically you assume that every quest will definitely have some relation to NPC (in that case) and if there is a quest than you return it. I thought it is possible to infer the relation to NPC by knowing thatquest
node exist. But I don't think in graphs so I am not sure if I should the logic use such logic for graph databases.
– lapots
Nov 20 '18 at 12:12
Yes, that's what I went for. If my assumption doesn’t harmonize with your concrete scenario, you could split the lastMATCH
clause in an obligatory part that identifies theQuest
and an optional part which finds the relatedNpc
, if there is one. Just now I have no Neo4j instance at hand unfortunately to verify the Cypher statement, but I think about something like this:MATCH (npc:Npc)-[:PROVIDES]->(quest:Quest), OPTIONAL MATCH (quest)-[:REWARDS]->(missing)
.
– ThirstForKnowledge
Nov 20 '18 at 12:42
In my case it is probablyoptional
match for quests andoptional
for npc.
– lapots
Nov 20 '18 at 13:25
add a comment |
The problem is that in this case I am not sure that theboots
orhelmet
can be only received as the rewards of quest. They might as well be a random drop from some mob. Or I have just tomatch
all possible cases in the query?
– lapots
Nov 20 '18 at 7:20
I’ve extended my answer to reflect your "quest only" requirement. Does the answer solve your challenge?
– ThirstForKnowledge
Nov 20 '18 at 10:37
I kinda get it now. So basically you assume that every quest will definitely have some relation to NPC (in that case) and if there is a quest than you return it. I thought it is possible to infer the relation to NPC by knowing thatquest
node exist. But I don't think in graphs so I am not sure if I should the logic use such logic for graph databases.
– lapots
Nov 20 '18 at 12:12
Yes, that's what I went for. If my assumption doesn’t harmonize with your concrete scenario, you could split the lastMATCH
clause in an obligatory part that identifies theQuest
and an optional part which finds the relatedNpc
, if there is one. Just now I have no Neo4j instance at hand unfortunately to verify the Cypher statement, but I think about something like this:MATCH (npc:Npc)-[:PROVIDES]->(quest:Quest), OPTIONAL MATCH (quest)-[:REWARDS]->(missing)
.
– ThirstForKnowledge
Nov 20 '18 at 12:42
In my case it is probablyoptional
match for quests andoptional
for npc.
– lapots
Nov 20 '18 at 13:25
The problem is that in this case I am not sure that the
boots
or helmet
can be only received as the rewards of quest. They might as well be a random drop from some mob. Or I have just to match
all possible cases in the query?– lapots
Nov 20 '18 at 7:20
The problem is that in this case I am not sure that the
boots
or helmet
can be only received as the rewards of quest. They might as well be a random drop from some mob. Or I have just to match
all possible cases in the query?– lapots
Nov 20 '18 at 7:20
I’ve extended my answer to reflect your "quest only" requirement. Does the answer solve your challenge?
– ThirstForKnowledge
Nov 20 '18 at 10:37
I’ve extended my answer to reflect your "quest only" requirement. Does the answer solve your challenge?
– ThirstForKnowledge
Nov 20 '18 at 10:37
I kinda get it now. So basically you assume that every quest will definitely have some relation to NPC (in that case) and if there is a quest than you return it. I thought it is possible to infer the relation to NPC by knowing that
quest
node exist. But I don't think in graphs so I am not sure if I should the logic use such logic for graph databases.– lapots
Nov 20 '18 at 12:12
I kinda get it now. So basically you assume that every quest will definitely have some relation to NPC (in that case) and if there is a quest than you return it. I thought it is possible to infer the relation to NPC by knowing that
quest
node exist. But I don't think in graphs so I am not sure if I should the logic use such logic for graph databases.– lapots
Nov 20 '18 at 12:12
Yes, that's what I went for. If my assumption doesn’t harmonize with your concrete scenario, you could split the last
MATCH
clause in an obligatory part that identifies the Quest
and an optional part which finds the related Npc
, if there is one. Just now I have no Neo4j instance at hand unfortunately to verify the Cypher statement, but I think about something like this: MATCH (npc:Npc)-[:PROVIDES]->(quest:Quest), OPTIONAL MATCH (quest)-[:REWARDS]->(missing)
.– ThirstForKnowledge
Nov 20 '18 at 12:42
Yes, that's what I went for. If my assumption doesn’t harmonize with your concrete scenario, you could split the last
MATCH
clause in an obligatory part that identifies the Quest
and an optional part which finds the related Npc
, if there is one. Just now I have no Neo4j instance at hand unfortunately to verify the Cypher statement, but I think about something like this: MATCH (npc:Npc)-[:PROVIDES]->(quest:Quest), OPTIONAL MATCH (quest)-[:REWARDS]->(missing)
.– ThirstForKnowledge
Nov 20 '18 at 12:42
In my case it is probably
optional
match for quests and optional
for npc.– lapots
Nov 20 '18 at 13:25
In my case it is probably
optional
match for quests and optional
for npc.– lapots
Nov 20 '18 at 13:25
add a comment |
The coalesce function in Neo4j can be used to compress multiple variables to use the most relevant, non-null value.
MATCH (w:Armor)<-[:WEARS]-(p:Player)
MATCH (w)-[:PART_OF]->(set:ArmorSet)
MATCH (missing)-[:PART_OF]->(set)
MATCH (missing)<--(anything)
WHERE NOT (p)-[:WEARS]->(missing)
OPTIONAL MATCH (anything)<-[:GIVES]-(source)
RETURN missing, coalesce(source, anything) as source
So in this example, coalesce will return the value of source if their is one, otherwise it will move to the next one and repeat. If all values are null, it will return null.
add a comment |
The coalesce function in Neo4j can be used to compress multiple variables to use the most relevant, non-null value.
MATCH (w:Armor)<-[:WEARS]-(p:Player)
MATCH (w)-[:PART_OF]->(set:ArmorSet)
MATCH (missing)-[:PART_OF]->(set)
MATCH (missing)<--(anything)
WHERE NOT (p)-[:WEARS]->(missing)
OPTIONAL MATCH (anything)<-[:GIVES]-(source)
RETURN missing, coalesce(source, anything) as source
So in this example, coalesce will return the value of source if their is one, otherwise it will move to the next one and repeat. If all values are null, it will return null.
add a comment |
The coalesce function in Neo4j can be used to compress multiple variables to use the most relevant, non-null value.
MATCH (w:Armor)<-[:WEARS]-(p:Player)
MATCH (w)-[:PART_OF]->(set:ArmorSet)
MATCH (missing)-[:PART_OF]->(set)
MATCH (missing)<--(anything)
WHERE NOT (p)-[:WEARS]->(missing)
OPTIONAL MATCH (anything)<-[:GIVES]-(source)
RETURN missing, coalesce(source, anything) as source
So in this example, coalesce will return the value of source if their is one, otherwise it will move to the next one and repeat. If all values are null, it will return null.
The coalesce function in Neo4j can be used to compress multiple variables to use the most relevant, non-null value.
MATCH (w:Armor)<-[:WEARS]-(p:Player)
MATCH (w)-[:PART_OF]->(set:ArmorSet)
MATCH (missing)-[:PART_OF]->(set)
MATCH (missing)<--(anything)
WHERE NOT (p)-[:WEARS]->(missing)
OPTIONAL MATCH (anything)<-[:GIVES]-(source)
RETURN missing, coalesce(source, anything) as source
So in this example, coalesce will return the value of source if their is one, otherwise it will move to the next one and repeat. If all values are null, it will return null.
answered Nov 20 '18 at 14:05
TezraTezra
5,07821143
5,07821143
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.
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%2f53380333%2fperform-additional-match-if-the-return-node-has-a-certain-type%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