Match all relationships between all nodes of a given set of labels

50 Views Asked by At

I have a graph with lots of distinct labels. I now want to select all nodes of a given subset of labels and all relationships between them.

I was able to get the expected result with the solution from How to get all relationships between a set of nodes?:

MATCH (m:A|B|C)-[r]->(n:A|B|C)
RETURN m, r, n

but this feels too repetitive. How can I avoid specifying the set of labels, i.e. A|B|C, twice?

I tried the following, but it doesn't return all relationships, but only those between a node and itself:

MATCH (n:A|B|C)-[r]->(n)
RETURN r, n

I'm looking for something like $labels = :A|B|C MATCH (m:$labels)-[r]->(n:$labels)


Sample data:

CREATE (a:A)-[:R]->(b:B)<-[:R]-(c:C)<-[:R]-(c)<-[:R]-(a)-[:R]->(d:D)

I want the query to return:

  • (a)->(b)
  • (c)->(b)
  • (c)->(c)
  • (a)->(c)
3

There are 3 best solutions below

2
Arne On

Unfortunatley, dynamic labels are not a thing in Cypher, yet.

The following query is a lot more verbose but it does not have the repetition. So, depending on your label expression, that may pay off:

MATCH (x:A|B|C)
WITH collect(x) as nodes
UNWIND nodes as m
UNWIND nodes as n
MATCH (m)-[r]->(n)
RETURN m, r, n;
2
Christophe Willemsen On

Here is a more efficient query than the one provided by Arne and also more efficient than providing the labels twice, somehow weird but the query profiles show so.

MATCH (n:Person|Movie)
WITH collect(n) AS nodes
MATCH (n)-[r]->(o)
WHERE n IN nodes AND o IN nodes
RETURN n, r, o
0
cybersam On

Since your query only repeats the list of labels once, I wouldn't say its "very" repetitive :-).

  1. But if you wanted to, you could just give all the nodes with the desired labels an additional label, say X (as in: MATCH (m:A|B|C) SET m:X), and then just do:

    MATCH (m:X)-[r]->(n:X)
    RETURN m, r, n
    

    This would take a little time to set up (and perhaps tear down afterwards), would create more overhead during creation of those nodes, and would use more storage, but it is a solution if this issue is important enough to you.

  2. Another solution is to use apoc.cypher.run with a generated Cypher query where the labels come from the same string:

    WITH ":A|B|C" AS labs
    CALL apoc.cypher.run("MATCH (m" + labs +")-[r]->(n" + labs + ") RETURN m, r, n", {}) YIELD value
    RETURN value.m AS m, value.r AS r, value.n AS n