Negation of Relationship


(Rcfro2) #1
match  (m:Movie)
where m.title contains "Matrix"
match (c:Person)-[:ACTED_IN]-(d)
where not (c)-[:ACTED_IN]->(m) 
return distinct c.name
order by c.name asc

Trying to find all people who didnt act in a Matrix movie. Is there an easier way?


(Michael Hunger) #2

Actually your query finds people who didn't act in one specific matrix movie but they could have acted in others.

match  (m:Movie) where m.title contains "Matrix" with collect(m) as movies
match (c:Person) where size[(c)-[:ACTED_IN]->(d) WHERE d IN movies] = 0 
return c.name
order by c.name asc

or

match  (m:Movie) where m.title contains "Matrix" with collect(m) as movies
match (c:Person)-[:ACTED_IN]->(d)
with c, collect(d) as actorMovies where none(m in movies where m in actorMovies)
return c.name
order by c.name asc

(Rcfro2) #4

Hmm...But the first two statements collect all the Movies with a title that contains "Matrix" in it - if you return right after that, that's the result you get.

Then, if you run this:
match (m:Movie)
where m.title contains "Matrix"
match (c:Person)-[:ACTED_IN]-> (m)
return c.name, m.title

You get a list of all actors/actresses of all Matrix movies because of the first two statements. So, how is my resulting query only specific to one Matrix movie?

Also, both your queries return an error :confused:


(few minutes later)
Modified your second query and seems to work -

match  (m:Movie) where m.title contains "Matrix" with collect(m) as movies
match (c:Person)-[:ACTED_IN]->(d)
with d, c, movies, collect(d) as actorMovies where none(m in movies where m in actorMovies)
return c.name
order by c.name asc

But it returns the wrong results. Keanu Reeves, for example, shows up in that result.


(Michael Hunger) #5

remove the d you don't want to aggregate by the movie. but only by the person

match  (m:Movie) where m.title contains "Matrix" with collect(m) as movies
match (c:Person)-[:ACTED_IN]->(d)
with c, movies, collect(d) as actorMovies where none(m in movies where m in actorMovies)
return c.name
order by c.name asc

(Rcfro2) #7

Can you explain why the query I have doesnt work? That was really my question. Why every other part seems to return what I am looking for but the last few statements do not. See explanation below:

Hmm...But the first two statements collect all the Movies with a title that contains "Matrix" in it - if you return right after that, that's the result you get.

Then, if you run this:
match (m:Movie)
where m.title contains "Matrix"
match (c:Person)-[:ACTED_IN]-> (m)
return c.name, m.title

You get a list of all actors/actresses of all Matrix movies because of the first two statements. So, how is my resulting query only specific to one Matrix movie?


(Michael Hunger) #8

Because the match is executed per row.

Imagine an actor only played in one matrix movie.

so you get 3 rows of matrix movies

and for each of them the person is checked against one
with the negation filtering it out, per movie

so the person is filtered out once and kept twice

so in the end you have the person still returned.


(Andrew Bowman) #9

The thing to keep in mind is to only treat a variable as a list of values if it's a collection (either you've used collect() to generate it or a pattern comprehension or from a procedure or function that returns lists).

If it's just a variable to a node match (even if potential several nodes match), that variable will only represent a single possible value per row, it can't be treated as a list of all matching variables.