1

I have the following query that is working as expected in neo4j. The query matches and collects distinct FEATURE, THREAT, GAP, FACT, and SCENARIO nodes with their relationships based on a specific feature key, then uses APOC procedures to create virtual relationships between these nodes for visualization, ensuring each node pair has its correct relationship type.

MATCH (fe:FEATURE)-->+(t:THREAT)-->+(g:GAP) 
MATCH (g)<--+(fa:FACT) 
MATCH (s:SCENARIO)<--+(g)
where fe.key= "Test S3 Storage#347585d0-e092-4808-a492-7b7a38e04dcd"

// Collect existing relationships and nodes
WITH collect(DISTINCT [fe, t]) + collect(DISTINCT [t, g]) AS hases,
     collect(DISTINCT [fa, g]) AS requireses,
     collect(DISTINCT [s, g]) AS scenarioGaps

// Create virtual relationships
WITH COLLECT { 
        WITH hases 
        UNWIND hases AS pair 
        RETURN [pair[0], apoc.create.vRelationship(pair[0], 'HAS', {}, pair[1]), pair[1]] AS tuple 
     } 
     + 
     COLLECT { 
        WITH requireses 
        UNWIND requireses AS pair 
        RETURN [pair[0], apoc.create.vRelationship(pair[0], 'REQUIRE', {}, pair[1]), pair[1]] AS tuple 
     } 
     + 
     COLLECT { 
        WITH scenarioGaps 
        UNWIND scenarioGaps AS pair 
        RETURN [pair[0], apoc.create.vRelationship(pair[1], 'HAS_SCENARIO', {}, pair[0]), pair[1]] AS tuple 
     }
     AS tuples

UNWIND tuples AS tuple

RETURN tuple[0], tuple[1], tuple[2]

Here is the issue I am facing:

  • There is a GAP node in my graph that I am querying which does not have a scenario node.
  • I want to include that GAP node without a scenario in my result of this graph.
  • If it is not directly possible, it is okay to add a place holder node there which will not be created in the real database.

I am unable to understand which approach should I use.

1 Answer 1

2

Try using OPTIONAL MATCH instead of MATCH for the (s:SCENARIO)<--+(g) pattern:

OPTIONAL MATCH (s:SCENARIO)<--+(g)

That allows the query to proceed when g has no path to a SCENARIO node. In that situation, the OPTIONAL MATCH would produce a NULL s value.

If you do that, then you would have to also change your last COLLECT subquery to ignore pairs that have a NULL first value.

For example:

MATCH (fe:FEATURE)-->+(t:THREAT)-->+(g:GAP) 
WHERE fe.key= "Test S3 Storage#347585d0-e092-4808-a492-7b7a38e04dcd"

MATCH (g)<--+(fa:FACT) 
OPTIONAL MATCH (s:SCENARIO)<--+(g)

// Collect existing relationships and nodes
WITH collect(DISTINCT [fe, t]) + collect(DISTINCT [t, g]) AS hases,
     collect(DISTINCT [fa, g]) AS requireses,
     collect(DISTINCT [s, g]) AS scenarioGaps

// Create virtual relationships
WITH COLLECT { 
        WITH hases 
        UNWIND hases AS pair 
        RETURN [pair[0], apoc.create.vRelationship(pair[0], 'HAS', {}, pair[1]), pair[1]] AS tuple 
     } 
     + 
     COLLECT { 
        WITH requireses 
        UNWIND requireses AS pair 
        RETURN [pair[0], apoc.create.vRelationship(pair[0], 'REQUIRE', {}, pair[1]), pair[1]] AS tuple 
     } 
     + 
     COLLECT { 
        WITH scenarioGaps 
        UNWIND scenarioGaps AS pair
        WITH pair
        WHERE pair[0] IS NOT NULL
        RETURN [pair[0], apoc.create.vRelationship(pair[1], 'HAS_SCENARIO', {}, pair[0]), pair[1]] AS tuple 
     }
     AS tuples

UNWIND tuples AS tuple

RETURN tuple[0], tuple[1], tuple[2]

Note that I also moved the top WHERE clause immediately under the first MATCH, to filter for the desired fe.key as early as possible.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.