perform additional match if the return node has a certain type












1














I've got a model that looks like this



enter image description here



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?










share|improve this question





























    1














    I've got a model that looks like this



    enter image description here



    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?










    share|improve this question



























      1












      1








      1







      I've got a model that looks like this



      enter image description here



      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?










      share|improve this question















      I've got a model that looks like this



      enter image description here



      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






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 20 '18 at 4:38









      ThirstForKnowledge

      6351112




      6351112










      asked Nov 19 '18 at 18:05









      lapotslapots

      3,6461360129




      3,6461360129
























          2 Answers
          2






          active

          oldest

          votes


















          2














          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.



          graph2



          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 an Armor, which is part of an ArmorSet".

          • Line 3 introduces the variable missing that is necessary for the exclusion "Player wears a missing Armor" 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 Armors retrieve the Quest providing Npcs

          • 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 Armors that can be retrieved by Quests 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);


          graph3



          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" │
          └─────────┴───────────┴──────────────────┘





          share|improve this answer























          • 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 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












          • In my case it is probably optional match for quests and optional for npc.
            – lapots
            Nov 20 '18 at 13:25



















          0














          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.






          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%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









            2














            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.



            graph2



            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 an Armor, which is part of an ArmorSet".

            • Line 3 introduces the variable missing that is necessary for the exclusion "Player wears a missing Armor" 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 Armors retrieve the Quest providing Npcs

            • 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 Armors that can be retrieved by Quests 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);


            graph3



            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" │
            └─────────┴───────────┴──────────────────┘





            share|improve this answer























            • 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 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












            • In my case it is probably optional match for quests and optional for npc.
              – lapots
              Nov 20 '18 at 13:25
















            2














            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.



            graph2



            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 an Armor, which is part of an ArmorSet".

            • Line 3 introduces the variable missing that is necessary for the exclusion "Player wears a missing Armor" 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 Armors retrieve the Quest providing Npcs

            • 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 Armors that can be retrieved by Quests 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);


            graph3



            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" │
            └─────────┴───────────┴──────────────────┘





            share|improve this answer























            • 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 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












            • In my case it is probably optional match for quests and optional for npc.
              – lapots
              Nov 20 '18 at 13:25














            2












            2








            2






            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.



            graph2



            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 an Armor, which is part of an ArmorSet".

            • Line 3 introduces the variable missing that is necessary for the exclusion "Player wears a missing Armor" 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 Armors retrieve the Quest providing Npcs

            • 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 Armors that can be retrieved by Quests 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);


            graph3



            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" │
            └─────────┴───────────┴──────────────────┘





            share|improve this answer














            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.



            graph2



            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 an Armor, which is part of an ArmorSet".

            • Line 3 introduces the variable missing that is necessary for the exclusion "Player wears a missing Armor" 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 Armors retrieve the Quest providing Npcs

            • 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 Armors that can be retrieved by Quests 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);


            graph3



            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" │
            └─────────┴───────────┴──────────────────┘






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Nov 20 '18 at 10:33

























            answered Nov 19 '18 at 22:37









            ThirstForKnowledgeThirstForKnowledge

            6351112




            6351112












            • 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 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












            • In my case it is probably optional match for quests and optional 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












            • 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












            • 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
















            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













            0














            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.






            share|improve this answer


























              0














              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.






              share|improve this answer
























                0












                0








                0






                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.






                share|improve this answer












                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.







                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Nov 20 '18 at 14:05









                TezraTezra

                5,02621042




                5,02621042






























                    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%2f53380333%2fperform-additional-match-if-the-return-node-has-a-certain-type%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

                    Can a sorcerer learn a 5th-level spell early by creating spell slots using the Font of Magic feature?

                    ts Property 'filter' does not exist on type '{}'

                    mat-slide-toggle shouldn't change it's state when I click cancel in confirmation window