Use MERGE on hyperedges with exact series of relationships

Viewed 37

TLDR: Is there a way to create a node (or to better say an hyperedge) only if it doesn't already exists but exactly with the specified series of relationships?

The long version is this one: suppose you have the following graph model, in which you describe different attacks. For each one of them you relate also the consequences of that particular attack (i.e. one "Attack" can have multiple "Consequence" node). Each consequence is also related to particular aspects such as security properties or impacts.

single hyperedge

So, to create this particular example I would do something like (suppose that the "Attack" node already exists):

MATCH (a:Attack {name:"Attack1"})
MERGE (i:Impact {name:"Execute unauthorized code"})
MERGE (p1:Property {name:"Confidentiality"})
MERGE (p2:Property {name:"Availability"})
MERGE (c:Consequence)-[:HAS_IMPACT]->(i)
MERGE (c)-[:AFFECTS]->(p1)
MERGE (c)-[:AFFECTS]->(p2)
MERGE (a)-[:HAS_CONSEQUENCE]->(c)

Now, suppose you want to add a second attack like this one:

merging new node

If I run the following Cypher code I don't get the expected result:

MATCH (a:Attack {name:"Attack2"})
MERGE (i:Impact {name:"Execute unauthorized code"})
MERGE (p:Property {name:"Confidentiality"})
MERGE (c:Consequence)-[:HAS_IMPACT]->(i)
MERGE (c)-[:AFFECTS]->(p)
MERGE (a)-[:HAS_CONSEQUENCE]->(c)

Basically due to the fact that the consequence of the "Attack2" is a subset of the "Attack1" I get this graph:

real result of the merge

To solve this problem I could use "CREATE" instead of "MERGE" when creating the "Consequence" node, but even this solution is not the perfect one, since it will create every time new nodes even if the right one already exists (with "right one" I mean the one that have the exact properties/impacts already related).

So, I was wondering if there's a specific approach to this kind of problem/situation.

1 Answers

If you want a new Consequence node, you can create it using CREATE simply like this:

MATCH (a:Attack {name:"Attack2"})
CREATE (c:Consequence)
MERGE (i:Impact {name:"Execute unauthorized code"})
MERGE (p:Property {name:"Confidentiality"})
MERGE (c)-[:HAS_IMPACT]->(i)
MERGE (c)-[:AFFECTS]->(p)
MERGE (a)-[:HAS_CONSEQUENCE]->(c)

There are only two ways of doing this, either use CREATE, or provide some unique property in the MERGE, so that MERGE can differentiate the Consequence nodes on the basis of that. Like this:

MATCH (a:Attack {name:"Attack1"})
MERGE (i:Impact {name:"Execute unauthorized code"})
MERGE (p1:Property {name:"Confidentiality"})
MERGE (p2:Property {name:"Availability"})
MERGE (c:Consequence{id: 1})-[:HAS_IMPACT]->(i)
MERGE (c)-[:AFFECTS]->(p1)
MERGE (c)-[:AFFECTS]->(p2)
MERGE (a)-[:HAS_CONSEQUENCE]->(c)

MATCH (a:Attack {name:"Attack2"})
MERGE (i:Impact {name:"Execute unauthorized code"})
MERGE (p:Property {name:"Confidentiality"})
MERGE (c:Consequence{id: 2})-[:HAS_IMPACT]->(i)
MERGE (c)-[:AFFECTS]->(p)
MERGE (a)-[:HAS_CONSEQUENCE]->(c)

This will create two different Consequence nodes because the id will vary. But again for every different id a node will be created, even if all other properties are the same. Just pick the one suitable for your use-case.

Related