dlman
dlman

Reputation: 54

Querying nodes based on relationships between two different nodes

I have a graph with two different types of nodes A and B connected by a relationship rel. It exists such that there may be multiple nodes of A connected to one of B. My exact problem is this, suppose I have 2 nodes a1, a2 of type A connected to b1 via the relationship rel. I have node a3 of type A related to node b2. I want to find a node b3 which contains a1, a2 and a3 and then form a relationship between b3 and b2, b1 if they fulfill a property(b3.prop/b2.prop>x & b3.prop/b1.prop>x). Is it possible to write a query in cypher that handles multiple relationships like this?

Upvotes: 0

Views: 212

Answers (1)

cybersam
cybersam

Reputation: 67044

This may work for your scenario:

MATCH (b1:B), (b2:B)
WHERE b1.id = 123 AND b2.id = 456
MATCH (a1:A)-[:rel]->(b1)
MATCH (a1)-[:rel]->(y1:B)
WHERE y1 <> b1 AND y1 <> b2
WITH b2, COLLECT(DISTINCT a1) AS a1s, COLLECT(DISTINCT y1) AS otherBs
WITH b2, [b IN otherBs WHERE ALL(a IN a1s WHERE (a)-[:rel]->(b))] AS candidates
WHERE SIZE(candidates) > 0
MATCH (a2:A)-[:rel]->(b2)
WITH candidates, COLLECT(a2) AS a2s
UNWIND [c IN candidates WHERE ALL(a IN a2s WHERE (a)-[:rel]->(c))] AS b3
RETURN b3

This query assumes the rel relationship is directed from A to B, and it will only return a result if there are any appropriate b3 nodes. It first creates a list of all the possible B candidates related to the A nodes related to b1. Then it whittles down the candidates list, keeping only the B nodes that are also related to the A nodes related to b2.

There are many nuances in this query. For example, this snippet would abort the query if any A node with a rel relationship to b1 does not also have a rel relationship to some other B node (that is not the same as b1 and b2):

MATCH (a1)-[:rel]->(b1)
MATCH (a1)-[:rel]->(y1:B)
WHERE y1 <> b1 AND y1 <> b2

Whereas the following refactoring of the above snippet would only abort the query if all A nodes with a rel relationship to b1 do not also have a rel relationship to some other B node (that is not the same as b1 and b2):

MATCH (y1:B)<-[:rel]-(a1)-[:rel]->(b1)
WHERE y1 <> b1 AND y1 <> b2

Upvotes: 1

Related Questions