Neo4j Cypher query - relationship with an "or" - neo4j

I'm trying to get a named relationship with an or in the query. I'm thinking the query should look similar to:
MATCH (A:person)-[B (:ACTED_IN|:DIRECTED)]->(C:person) RETURN A, B, C
but no matter how I put in the parens I get an error. I suppose a UNION would do the trick but was hoping that there was some way of doing it similar to the above. TIA.
EDIT: This does what I want but seems not the way to do it.
MATCH (A:person)-[B]->(C:person) WHERE type(B)="ACTED_IN" OR type(B)="DIRECTED" RETURN A,B,C

I am a new user so I do not have the option to comment on questions yet. I am guessing you are trying to get the person who either acted in or directed the movie. Its described in official Cypher Documentation: Match on multiple relationship types.
With Demo Movie Data on Neo4j to get persons from The Matrix movie, I would use this:
MATCH (TheMatrix { title: 'The Matrix' })<-[rel:ACTED_IN|:DIRECTED]-(person)
RETURN person.name, rel

Related

How to return the Node class or type in the query results in Neo4j

I have a node type Author, which is linked to node types Book and Magazine by the relationship type WROTE. I need to find all books and magazines a particular author wrote in a single query, and in the query results I want to be able to differentiate between the Book and the Magazine results.
One way I can achieve this is by defining separate relationships for Books and Magazines, and returning the TYPE(relationship) value in the results to match results for Books versus Magazines.
MATCH (a:Author)-[r]->(i) WHERE TYPE(r) = 'WROTE_BOOK' OR TYPE(r) = 'WROTE_MAGAZINE'
RETURN TYPE(r), i
However, I would like to be able to do this without having separate relationships for WROTE. Is there a way to query the node type or class in the query results? In the example above, something like below:
MATCH (a:Author)-[:WROTE]->(i) WHERE TYPE(i) = 'Book' OR TYPE(i) = 'MAGAZINE'
RETURN TYPE(i), i
It seems that the TYPE() function is only available for relationships, not for nodes. Thanks for your help in advance!
type is for relationships and labels is for nodes.
MATCH (a:Author)-[:WROTE]->(i) WHERE labels(i) in ['Book','MAGAZINE']
RETURN labels(i), i
if your author wrote only magazines and books, you do not need the WHERE filter.
MATCH (a:Author)-[:WROTE]->(i)
RETURN labels(i), i

AND operator is not working with type(r) in Neo4j

In the Movie Graph which comes with Neo4j as Sample graph, I want to query : Get the movie which has been directed and written by the same person who directed The Matrix movie.
Here is the query which i am using
Match(m:Movie{title:'The Matrix'})<-[r:DIRECTED]-(p:Person)-[r2]->(n:Movie)
where type(r2)='DIRECTED' and type(r2)='WROTE'
return p,n
This query is not working but if i will put OR clause instead of AND clause. It will work. Using OR clause giving me the list of movie which is written or directed by the same director who directed The Matrix movie. Please let me know why AND clause is not working with type(r).
If you have both relationships DIRECTED and WROTE between person and movie you will have two result lines, not one.
Like
a |type(r) |b
a |DIRECTED|b
a |WROTE |b
So when you set or, you get both lines. But when you say and you actually get nothing becaues Directed <>(Directed and Wrote) at the same time
If you mean that there should be both DIRECTED and WROTE relationships between person and Movie, query should be like
Match (m:Movie{title:'The Matrix'})<-[r:DIRECTED]-(p:Person)-[r2:DIRECTED]->(n:Movie),
(p)-[r3:WROTE]->(n)
return p,n
This is probably the most straightforward query for finding all movies that were both written and directed by the director of "The Matrix":
MATCH (:Movie{title:'The Matrix'})<-[:DIRECTED]-(p:Person)
MATCH (n:Movie)<-[:WROTE]-(p)-[:DIRECTED]->(n)
RETURN p,n;

Neo4J contains all Query

I'm brand new to neo4j and graph databases.
I'm trying to create a query I would describe as a 'contains all' however I think I'm very far away and not sure how to progress
MATCH (movie:Movie {name:'tropic thunder'})-[:stars_in]-(actors)
-[:guest_stars_in]-(movie2)
RETURN movie2.name
Let's say
MATCH (movie:Movie{name:'tropic thunder'})-[:stars_in]-(actors)
returns 5 actors
I'm looking to match exactly (all 5 actors -> same 5 actors as guest stars) or as a subset (all 5 actors are a subset of a movie which has 10 guest stars).
Hope that makes sense. Thanks for your help :D
The first thing I would point out is that you should call the variable actor instead of actors. It may seem picky, but it's a common confusion with Cypher. With the MATCH you are matching one sub-pattern at a time.
So to start out let's find each movie2 and get an array of the actors in question:
MATCH (movie:Movie {name:'tropic thunder'})-[:stars_in]-(actor)
-[:guest_stars_in]-(movie2)
RETURN movie2.name, collect(actor)
A first instinct might be to extend the path like so:
MATCH (movie:Movie {name:'tropic thunder'})-[:stars_in]-(actor)
-[:guest_stars_in]-(movie2)-[:guest_starts_in]-(actor2)
But again, we're matching every possible match of that path in the database. So for each actor, we're going to match all possible actor2s, which would lead to duplicates.
What we can do, though, is to take our first query and change the RETURN to a WITH in order to pass our data onto a second part of the query:
MATCH (movie:Movie {name:'tropic thunder'})-[:stars_in]-(actor)
-[:guest_stars_in]-(movie2)
WITH movie2, collect(actor) AS original_movie_actors
MATCH movie2-[:guest_stars_in]-(guest_star)
RETURN movie2.name, original_movie_actors, collect(guest_star) AS guest_stars
This gives us
a list of movies in question
the list of the actors who both stared in "tropic thunder" and guest stared in the movie in question
all guest stars for the movie in question
From here you could probably figure it out in your programming language of choice. But we can figure this out in Cypher too:
MATCH (movie:Movie {name:'tropic thunder'})-[:stars_in]-(actor)
-[:guest_stars_in]-(movie2)
WITH movie2, collect(actor) AS original_movie_actors
MATCH movie2-[:guest_stars_in]-(guest_star)
WITH movie2, original_movie_actors, collect(guest_star) AS guest_stars
RETURN
movie.name,
ALL(guest_star IN guest_stars WHERE guest_star IN original_movie_actors) AS all_matched,
length(original_movie_actors) / length(guest_stars) AS percentage_match
I threw in a percentage_match as a double-check and in case that's useful

Cypher path querying (using Neo4j)

I have a graph datebase so that there is in it some pattern like this one:
(n1)-[:a]->(n2),
(n1)-[:b]->(n2),
(n1)-[:c]->(n2),
(n1)-[:e]->(n2),
(n1)-[:d]->(n3),
(n2)-[:b]->(n4)
And I want to have all graph with this pattern
MATCH p={
(n3)<-[:d]-(n1)-[:a]->(n2)-[:b]->(n4),
(n1)-[:b]->(n2)<-[:c]-(n1),
(n1)-[:e]->(n2)
}
RETURN p
Is it possible? I've search a little but I haven't found how to do it.
I know we can use "|" for a type like this
()-[:a|b]->()
but there is no "&" and the path assigning only works on pattern which are written without ",".
Thanks
EDIT:
If it could help, here is another example of what I'm seeking:
In a database with movies, person and relations like ACTED_IN, KNOWS, FRIEND and HATE
I want all the graphs containing an actor "Actor1" (who ACTED_IN a movie "M") who KNOWS "Person1", FRIEND "Person2" and HATE "Person3" which ACTED_IN the same movie "M".
An UNION like the one in the answer of "Michael Hunger" does not work because we have multiple subgraphs and not graphs. Moreover, some subgraph might not be correct answers for the bigger pattern.
Your query will be very inefficient, as you don't restrict your search to a set of start nodes neither with labels or label+property combinations !!!!
You can use UNION for that:
MATCH p=(n3)<-[:d]-(n1)-[:a]->(n2)-[:b]->(n4) RETURN p
UNION
MATCH p=(n1)-[:b]->(n2)<-[:c]-(n1) RETURN p
UNION
MATCH p=(n1)-[:e]->(n2) RETURN p

Please clarify the query used in Neo4j online course

I am going through the online course at http://www.neo4j.org/learn/online_course.
In that under the section (Graph LAB) - (Paths), the below query was used to RETURN all of the actors and directors in all of the movies.
MATCH (a)-[:ACTED_IN]->(m)<-[:DIRECTED]-(d)
RETURN a.name, m.title, d.name;
It is perfectly alright.
To the next question "How would you change this query to RETURN only the directors who acted in their own movies?"
They gave the solution as change (d) to (a). So the query is,
MATCH (a)-[:ACTED_IN]->(m)<-[:DIRECTED]-(a)
RETURN a.name, m.title, a.name;
When i execute this query it throws output as "Unforgiven, Clint Eastwood".
But my doubt is when i look at the interactive network diagram, the node "Clint Eastwood" was connected to the "Movie" node only through the relationship "DIRECTED". There was not a separate relationship "ACTED_IN". Then how neo4j selects only "Unforgiven, Clint Eastwood" and discards other directors.
Please clarify this. Is my understanding wrong.
r karthik.
Yes, the DIRECTED relationship is overlaying the ACTED_IN one. You can see the ACTED_IN relationship after deleting the DIRECTED relationship:
MATCH (a)-[:ACTED_IN]->(m)<-[d:DIRECTED]-(a)
DELETE d;
I agree that the visualization should somehow avoid letting overlays like this happen. You should bring this to the attention of the neo4j folks. At the very least, they may want to change the tutorial to avoid this situation.
This works for me:
MATCH (a)-[:ACTED_IN]->(m)<-[:DIRECTED]-(a)
RETURN a.name, m.title;

Resources