Question regarding different results in intro-neo4j-exercises 4

Hey guys,
in exercises 4, I get two different results for two queries that looks similar to me.
I would love to understand why these two queries gives 2 different results.

the queries are running on top the movie db.

First one:
MATCH (a:Person)-[:PRODUCED]->(m:Movie)
WHERE NOT ((a)-[:DIRECTED]->(:Movie))
RETURN a.name, m.title

returning 7 records

Second:
MATCH (p:Person)-[rel]->(m:Movie)
WHERE type(rel)='PRODUCED' AND NOT(type(rel)='DIRECTED')
RETURN p.name, m.title

returning 15 records

Thanks in advance!

Another question on the same exercise, would love help to understand the idea:

MATCH (m:Movie)<-[rel]-(p:Person)
WHERE rel.roles in m.title
RETURN m.title as Title, rel.roles as Role

returns no results

MATCH (m:Movie)<-[rel]-(p:Person)
WHERE m.title in rel.roles
RETURN m.title as Title, rel.roles as Role

returns 4 records

it suppose to be one to one match. Why doesn't it work on both queries? (when title in roles AND when roles in title)

Thanks in advance!

In the first query, you're matching to patterns of a person who produced movies, where that person has never directed any movie. So this query excludes any director.

In the second query, you're matching to a pattern of a person having a relationship to a movie, where FOR EACH OF THOSE RELATIONSHIPS, that particular relationship is a :PRODUCED relationship and not a :DIRECTED relationship. Since an individual relationship can only have a single type, it is impossible for a :PRODUCED relationship to also be a :DIRECTED relationship, so all :PRODUCED relationships fit the pattern. By that logic, this query doesn't exclude directors.

If you're having any trouble understanding this, try outputting the results with the restriction on the produced type, but not on the directed type:

MATCH (p:Person)-[rel]->(m:Movie)
WHERE type(rel) = 'PRODUCED'
RETURN p.name, m.title, id(rel), type(rel) as type

Notice the type result. It will be 'PRODUCED'. There is no way for it to also be 'DIRECTED', so it fits your criteria. Notice also that per row, rel is referring to a single specific relationship (and the same holds true for variables on nodes).

1 Like

These are not one to one. Remember that you're working with different types. m.title is a string. rel.roles is a list.

Here's the results of the second query:

╒═════════════════╤═══════════════════╕
│"Title"          │"Role"             │
╞═════════════════╪═══════════════════╡
│"Jerry Maguire"  │["Jerry Maguire"]  │
├─────────────────┼───────────────────┤
│"Johnny Mnemonic"│["Johnny Mnemonic"]│
├─────────────────┼───────────────────┤
│"Speed Racer"    │["Speed Racer"]    │
├─────────────────┼───────────────────┤
│"Hoffa"          │["Hoffa"]          │
└─────────────────┴───────────────────┘

You can easily see that the roles lists contain an element equal to the movie title.

But the title is not a list. By convenience, when you're using a variable where a list is expected, it will change it into a single element list for you, so that's fine. But the item that you're checking for membership isn't a string, it's another list!

So "Jerry Maguire" the string does not contain a single-element list of ["Jerry Maguire"].
And the coerced ["Jerry Maguire"] that Cypher will use still does not contain the single-element list of ["Jerry Maguire"]. It does contain the string "Jerry Maguire", but that's not what you're asking it to check.

So if you do want to get this to work the way you want, you need to get the element FROM the list and see if it's in the property value. This works:

MATCH (m:Movie)<-[rel]-(p:Person)
WHERE rel.roles[0] in m.title
RETURN m.title as Title, rel.roles as Role

And if you want to see if ANY element in the list is in the title, then you can use a list predicate instead:

MATCH (m:Movie)<-[rel]-(p:Person)
WHERE any(role in rel.roles WHERE role in m.title)
RETURN m.title as Title, rel.roles as Role

Though as mentioned you normally wouldn't use this approach at all, just stick with WHERE m.title IN rel.roles

1 Like