Understanding the all() Predicate Function

I'm trying to use the all() Predicate Function in my query, but it's not working as expected, so I decided to experiment a little with the Movies graph.

Given that I want to find all paths where actors acted in movies that were released after 2000, I tried using the all() function, like so -

MATCH path=(p:Person)-[:ACTED_IN]->(movie:Movie)
WHERE all(n in nodes(path) WHERE (n:Movie) AND n.released > 2000)
RETURN path
LIMIT 20

This is similar to the example given in the documentation, that says -

MATCH p =(a)-[*1..3]->(b)
WHERE a.name = 'Alice' AND b.name = 'Daniel' AND ALL (x IN nodes(p) WHERE x.age > 30)
RETURN p

All nodes in the returned paths will have an age property of at least '30' .

However, my query doesn't return anything.

If I change the query to see all nodes in the path -

MATCH path=(p:Person)-[:ACTED_IN]->(movie:Movie)
RETURN nodes(path)
LIMIT 20

Then there are several nodes in the path where the movie was released after 2000 -

Screenshot_2020-01-14 neo4j bolt ws-10-0-1-171-32904 neo4jsandbox com 443 - Neo4j Browser(1)

Is there something I'm missing about how all() works?

HI manish ,
MATCH path=(p:Person)-[:ACTED_IN]->(movie:Movie)
WHERE all(n in nodes(path) WHERE (n:Movie) AND n.released > 2000)
RETURN path
LIMIT 20

in this query , when you do ALL() , it means all the nodes in that path must qualify the filter you put inside that i.e n: Movie AND n.released > 2000
But , here, when you do nodes(path) , it includes the p:Person node too , so the person node cannot qualify the n:Movie filter .. since one node failed the condintion, ALL () will also fail .. thats why it wont return any output in anycase.

Instead, you can do the following ,
MATCH path=(p:Person)-[:ACTED_IN]->(movie:Movie)
WHERE movie.released > 2000
WITH p , movie LIMIT 20
RETURN p , COLLECT(movie) as movies

Hello, Thank You for responding!

I have a question about this -

I was under the impression that my query would only consider nodes of type Movie in nodes(path), because I specifically added in this clause - WHERE (n:Movie),
before adding AND n.released 2000.

I thought this would select only the Movie nodes from the path, and apply the released > 2000 filter on those Movie nodes, because obviously the released property exists only on Movie nodes.

nodes(path) -> this function will return all nodes the in the path ,
ex : nodes(path) = [ personNode , movieNode]
ALL (x IN nodes(path) WHERE (condition))
so , you are iterating through [ personNode , movienode,movie node] and applying filter ,
the filter fails with person node and so the ALL function .

When you do n:Movie ,you are asking to filter nodes(note that you are not selecting) which have label Movie, this means your filter returns true for all movie nodes but false for person node.
but ALL() wants all the rows passed to satisfy the where condition (ie.return true)

WHERE is for filtering the selected rows ..MATCH does the actual select part

Consider the results in the image you posted. Each row here contains a list of the nodes in the path (or at least it displays their properties). Because of your pattern (p:Person)-[:ACTED_IN]->(movie:Movie), each path will consist of two nodes: a :Person node and a :Movie node that the person acted in.

Since you're using all(n in nodes(path) ..., that means, per path, every one of those nodes needs to adhere to your WHERE clause: every node needs to be a :Movie node (which is impossible because of your pattern), and each node needs a released property > 2000.

If you had used any() instead of all(), then the predicate would be satisfied by finding, in the path, at least one node satisfying the conditions, and you would have gotten results back.

Thank You! I guess the comparison between all() and any() makes it clear. For some reason, I thought using WHERE, like (WHERE (n:Movie)), inside all() would first filter out all Movie nodes, and then apply the all() predicate for all such nodes.

I can see how that could seem confusing. You would need to filter the list used separately.

For example, if we wanted to filter the nodes in the path to only be :Movie nodes and then filter by the released property you could do this:

MATCH path=(p:Person)-[:ACTED_IN]->(movie:Movie)
WHERE all(n in [node in nodes(path) WHERE node:Movie] WHERE (n:Movie) AND n.released > 2000)
RETURN path
LIMIT 20

So rather than just use nodes(path), we need to filter this first, in this case using a list comprehension to filter the list such that every node in nodes(path) meets the criteria of being a :Movie node. Now that the list is filtered to only be :Movie nodes (these should be single-element lists now), the all() list predicate may evaluate to true for some of the paths matched.

1 Like

Thank You so much! Your explanation makes it a lot more clearer.

Just so I know I'm getting it right -

this is done using this list comprehension - [node in nodes(path) WHERE node:Movie]

If this works, then, from what I think, the resulting list should contain only Movie nodes? If that is the case, then would it be correct to remove the redundant WHERE (n:Movie) in the any() function, so that it becomes -

WHERE all(n in [node in nodes(path) WHERE node:Movie] WHERE n.released > 2000)

I did run this query, and it seems to return something, so I'm guessing this must be correct -

Yes, just like that!

Of course the usage of all() makes more sense in a longer pattern, one with multiple :Movies nodes, or a pattern where you may not know which node types are involved or how many, but you want to make sure that all :Movies nodes in the path were released after 2000.