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:
I am unable to understand which approach should I use.
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 pair
s 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.