Search code examples
neo4jcypher

Running two partially related cypher queries together


I need to fetch two related collections from a Neo4j database.

The first one is to get some things that satisfy a list of conditions, something like this:

MATCH (n:Thing)
WHERE [complicated list of conditions]
RETURN n
ORDER BY n.label
LIMIT 25

the second one is to get nodes related to the nodes that satisfy the conditions, something like this:

MATCH (m:RelatedThing) -[:Relationship]-(n:Thing)
WHERE [same complicated conditions about n]
RETURN m
ORDER BY m.label 
LIMIT 25

Crucially, the m's don't have to be related to the first 25 n's that were returned by query 1.

It seems like there is a lot of repetition between these two queries. Is there a way to run them both in a single query?

Obviously this can be done in two queries, but reading around I haven't found a good way to run both queries together. It seems like maybe COLLECT could be useful, but it doesn't quite fit the use case.

EDIT: I am looking for a solution that works in version 3.5.12


Solution

  • You can use two CALL subqueries:

    MATCH (n:Thing) WHERE < complicated list of conditions >
    WITH COLLECT(n) AS list
    CALL {
      WITH list
      UNWIND list AS x
      WITH x
      ORDER BY x.label LIMIT 25
      RETURN COLLECT(x) AS list1
    }
    CALL {
      WITH list
      UNWIND list AS y
      MATCH (m:RelatedThing)-[:Relationship]-(y)
      WITH DISTINCT m
      ORDER BY m.label LIMIT 25
      RETURN COLLECT(m) AS list2
    }
    RETURN list1, list2
    

    For very old neo4j versions without CALL subquery

    The APOC procedure apoc.cypher.run has been supported for a long time, and can be used instead of the more recent CALL subquery feature:

    MATCH (n:Thing) WHERE < complicated list of conditions >
    WITH COLLECT(n) AS list
    CALL apoc.cypher.run("
      UNWIND list AS x
      WITH x
      ORDER BY x.label LIMIT 25
      RETURN COLLECT(x) AS list1",
      {list: list}
    ) YIELD value as val1
    CALL apoc.cypher.run("
      UNWIND list AS y
      MATCH (m:RelatedThing)-[:Relationship]-(y)
      WITH DISTINCT m
      ORDER BY m.label LIMIT 25
      RETURN COLLECT(m) AS list2",
      {list: list}
     ) YIELD value as val2
    RETURN val1.list1 AS list1, val2.list2 AS list2