I'm trying to write a Cypher query that will return all node sets that satisfy every specified condition. For example, if we have (Actor) - [ACTING] - (Movie), (Director) - [DIRECTING] - (Movie) and (Composer) - [COMPOSING_MUSIC] - (Movie); and query like: Actor1 Movie1 Director1 Actor2 Movie1 Director1 Actor2 Movie2 Director2 Actor1 Movie3 Director3 Composer1
What are the sets of nodes (Actor), (Movie), (Director), (Composer) that satisfy All constraints from above?
I tried Matching each edge
match (a1:Actor)-[:ACTING]-(m1:Movie),
(a2:Actor)-[:ACTING]-(m1:Movie),
...
(d1:Director)-[:DIRECTING]-(m1:Movie),
(d2:Director)-[:DIRECTING]-(m2:Movie),
...
where a1<>a2 and d1<>d2 ...
However, this will give me a cross matching with every match statement. So my result set will becom larger (instead of smaller) with each new constraint. Is there a canonic way of solving these typo of problems? The next edge(constraint) should be only within filtered (previous) results?
Thank you
You did not specify the directionality of your relationships, so in my answer I am going to assume that all your relationships are directed towards Movie
nodes. For example: (:Actor)-[:ACTING]->(:Movie)
.
The following queries avoid creating a cartesian product, as the outer MATCH
just creates one row for each movie, and each COLLECT
just adds one value (a list) to each row (instead of multiplying the number of rows).
This query uses the COLLECT subquery clause (available in neo4j 5.6+) to return a list of the actors, directors, and composers for each movie:
MATCH (m:Movie)
RETURN m,
COLLECT{ MATCH (m)<-[:ACTING]-(a) RETURN a } AS actors,
COLLECT{ MATCH (m)<-[:DIRECTING]-(d) RETURN d } AS directors,
COLLECT{ MATCH (m)<-[:COMPOSING_MUSIC]-(c) RETURN c } AS composers
This query uses the CALL subquery clause, which has existed for a long time, to accomplish the same thing:
MATCH (m:Movie)
CALL{ WITH m MATCH (m)<-[:ACTING]-(a) RETURN COLLECT(a) AS actors }
CALL{ WITH m MATCH (m)<-[:DIRECTING]-(d) RETURN COLLECT(d) AS directors }
CALL{ WITH m MATCH (m)<-[:COMPOSING_MUSIC]-(c) RETURN COLLECT(c) AS composers }
RETURN m, actors, directors, composers