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
ageproperty 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 -
Is there something I'm missing about how
HI manish ,
WHERE all(n in nodes(path) WHERE (n:Movie) AND n.released > 2000)
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 ,
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
nodes(path), because I specifically added in this clause -
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
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.
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.
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 -