I've just recently started using neo4j and I've run into an issue. There doesn't seem to be an answer to this on here but I might also be wording it incorrectly. I'm building a small site that categorizes music. There are multiple song nodes with BELONGS_TO relationships to genre nodes. How can I get every song that belongs to a set of user specified genres.
For example. Song1, Song2, Song3 all belong to both Pop and Electronic. Song4 just belongs to Pop. How can I query to get every song belonging to both Pop and Electronic? In this case Song1, Song2, an Song3.
I've been struggling with this for a while. This is what I have so far but it doesn't return anything. If I replace AND with OR I get all the songs that belong to one of those genres.
MATCH (n:Song)-[r:BELONGS_TO]->(Genre)
WHERE (n)-[r]->(Genre{name:"Pop"}) AND (n)-[r]->(Genre{name:"Electronic"})
RETURN n
Thank you.
What you're trying to do in the WHERE clause you should actually do in the MATCH clause. Here you go:
MATCH (g1:Genre {name: "Pop"})<-[:BELONGS_TO]-(popElectronicSongs:Song)-[:BELONGS_TO]->(g2:Genre {name: "Electronic"});
RETURN popElectronicSongs;
You can actually do quite a lot with just the MATCH clause as you can see here. The WHERE bit usually gets used for filtering based on various predicates. For example you might say WHERE popElectronicSongs.title =~ /S.*/ to filter for only songs whose name starts with S.
Related
I have a database containing movies and users. Users can follow each other and rate movies. I have a user with the id 599. I want to find all the movies he hasn't watched that the other users he follows have watched. Here's what I tried so far. I do get a result and it works but the numbers don't really add up so I think there might be something off.
MATCH (u:user {id:599}),(m2:Movie), (u2:user),(u)-[r]->(u2),(u2)-->(m2)
WHERE not (u)-->(m2)
RETURN m2.title, m2.movieId,u2.id;
As #Inversefalcon stated, perhaps your query needs to be specific about the relationship types, in case there are multiple types of relationships between the same nodes.
For example (assuming your data model has the relationship types FOLLOWS and WATCHED):
MATCH (u:user {id:599})-[:FOLLOWS]->(u2:user)-[:WATCHED]->(m2:Movie)
WHERE not (u)-[:WATCHED]->(m2)
RETURN m2.title, m2.movieId, u2.id;
If this does not solve your issue, then please provide some sample data and what your expected number of results is.
I'm new to Neo4j and have been playing with an idea about people moving houses, in order to learn more about cypher. This is what I have currently
Each Person [:OWNS] a House
Each House [:ISIN] a Street
A Person [:WANTS] (to live in) a Street
The aim is to find a complete 'chain'
If I run
MATCH (s:Street)<-[:WANTS]-(p:Person)-[:OWNS]->(h:House) RETURN s,h,p
This returns me the complete chain linking right back to the person.
What I'm trying to do is only return complete chains and not broken ones.
I've also tried
MATCH (s:Street)<-[:WANTS]-(p:Person)-[:OWNS]->(h:House)-[:ISIN]->(s) RETURN s,h,p
but this never returns results. Any thoughts?
UPDATE
I got the last query returning results by doing this
MATCH (s:Street)<-[:WANTS]-(p:Person)-[:OWNS]->(h:House)-[:ISIN]->(s1: Street) RETURN s,h,p
But am not sure if this is what I want.
I just want to return circular results so I can see complete house moving chains. Ultimately based on one person so I'll need to put a WHERE in there.
I will try move queries tomorrow with a larger dataset
MATCH won't repeat a node in a chain, aka a single match can't match the same node in two variables. But you can just break out the last chain to a where clause
MATCH (s:Street)<-[:WANTS]-(p:Person)-[:OWNS]->(h:House)
WHERE (h)-[:ISIN]->(s)
RETURN s,h,p
I am trying to discover how many hops I have to do to know a friend with Cipher. I have these relationships.
(Gutierrez)-[:Conhece]->(Felipe),
(Felipe)-[:Conhece]->(Gutierrez),
(Felipe)-[:Conhece]->(Fernando),
(Fernando)-[:Conhece]->(Felipe),
(Fernando)-[:Conhece]->(Pedro),
(Pedro)-[:Conhece]->(Fernando),
(Pedro)-[:Conhece]->(Arthur),
(Arthur)-[:Conhece]->(Pedro),
(Arthur)-[:Conhece]->(Vitor),
(Vitor)-[:Conhece]->(Arthur),
and when I execute my query it shows Fernando. What I want is to show only Vitor, Pedro and Arthur.
MATCH (n:Leitor)-[r:Conhece]-m
WHERE n.nome='Pedro' OR m.nome='Vitor'
RETURN n,r,m
with my Bacon Path query ->
Ok, I'm adding another answer because I think I understand what you want and it's different than my other answer.
If you want to find everybody that both Pedro and Vitor have met (in this case, just Author):
MATCH (pedro:Leitor)-[:Conhece]-(in_common:Leitor)-[:Conhece]-(vitor:Leitor)
WHERE pedro.nome='Pedro' AND vitor.nome='Vitor'
RETURN in_common
That also might look a bit better like this:
MATCH (pedro:Leitor {nome: 'Pedro'})-[:Conhece]-(in_common:Leitor)-[:Conhece]-(vitor:Leitor {name: 'Vitor'})
RETURN in_common
I also notice from your screenshots that every meeting has two relationships. That may very well be what you want, but if your plan was to always have two relationships whenever two people meet then you can get away with just one relationship. When you query bidirectionally (that is, without specifying direction like in the queries above) then you'll get relationships in either direction.
Normally you only want relationships going in both directions if the direction is important. That could be because your just recording that it goes from one node to another, or it could be because you're storing different values on the relationships.
Here you go:
MATCH shortestPath((n:Leitor)-[rels:Conhece*]-m)
WHERE n.nome IN ['Pedro', 'Vitor']
RETURN n,rels,m,length(rels)
In this case rels will be a collection of relationships because the path is variable length. You can also do:
MATCH path=shortestPath((n:Leitor)-[rels:Conhece*]-m)
WHERE n.nome IN ['Pedro', 'Vitor']
RETURN n,rels,m,length(rels),path,length(path)
I have read the Neo4j manual and saw the numerous short examples regarding movie graph. I have also installed it locally and played with the cypher.
Here is the setup:
I have the following nodes: Movies (with name and id, owned by friend), Actors(with name and ids) Directors (with names and id), Genre (with id and name)
Relations are: Actors acted in Movies (1 movie - many actors), Directors directed a movie (1 director per movie but a director can direct many movies), and Movies has several genre "(many to many)
1) Owned by friend I dont know why but following the LOAD CSV example they put USA as a node rather than a property but is there a logical reason why its better to put it as a node rather than a property like i did?
2)
What I want to search is similar to the answer given to this question:
Nearest nodes to a give node, assigning dynamically weight to relationship types
However - I do not have a weight on the relationship and its more of a "go find the first give nodes connected to it"
Given that the "owned by friend" can only be owned by 1 person.
If given movie title "Spider-Man" (which for example purpose is owned by frank) go find the next occurrence of a movie that is owned by John.
So after reading Neo4j I believe that I dont need to specify which relationship is needed to traverse but just go find the next movie that meets my criteria, right?
So Following the above link
MATCH (n:Start { title: 'Spider-Man' }),
(n)-[:CONNECTED*0..2]-(x)
RETURN x
So go to node Spider-Man and go find me X as long as it is connected but I got stump by *0..2 because its the range...what if I just say "go find me the first you that means the own by John"
3) following up to #2 - how do i insert the fitler "own by john" ?
There are a number of things in your question that don't quite make sense. Here's a stab at an answer.
1) Making 'USA' a node rather than a property is useful if you want to search based on country. If 'USA' is a node, you are able to limit your search by starting at the 'USA' node. If you don't care to do this, then it doesn't really matter. It may also save a small amount of space for longer country names to store the name once and link to it via relationships.
2) Your example doesn't match your described graph. I can't really speak to it without a better example.
3) This is probably easy to answer once you improve your example.
OK. Based on the comments to the answer, here's what you need. To find one movie owned by John that is connected via common actors, directors, etc to the movie Spider-man owned by Frank (that is, sub-graphs like (movie)<--(actor)-->(movie) ) you can write:
MATCH (n:Movie {title : 'Spider-Man', owned_by : 'Frank'})<-[*2]->(m:Movie {owned_by : 'John'})
RETURN m LIMIT 1
If you want more responses, alter or remove the LIMIT on the RETURN clause. If you want to allow chains that pass through chains like (movie)<--(actor)-->(movie)<--(director)-->(movie), you can increase the number of relationships matched (the *2) to 4, 6, 8, etc. You probably shouldn't just write the relationship part of the MATCH clause as -[*]-, because this could get into infinite loops.
I've been playing around with Neo4j and have a problem for which I do not have a solution, hence my question here.
For my particular problem I'll describe a simplified version that captures the essence. Suppose I have a graph of locations that are connected either directly or via a detour:
direct: (A)-[:GOES_TO]->(B)
indirect: (A)->[:GOES_THROUGH]->(C)-[:COMES_BACK_TO]->(B)
If I want to have everything between "Go" and the "Finish" with a GOES_TO relationship I can easily use the Cypher query:
START a=node:NODE_IDX(Id = "Go"), b=node:NODE_IDX(Id = "Finish)
MATCH a-[r:GOES_TO*]->b
RETURN a,r,b
Here, NODE_IDX is an index on the nodes (Id).
Where I get stuck is when I want to have all the paths between "Go" and "Finish" that are not GOES_TO relationships but rather multiple GOES_THROUGH-->()-->COMES_BACK_TO relationship combinations (of variable depth).
I do not want to filter out the GOES_TO relationships because there are many more relationships among the nodes, and I do not want to accommodate removing all of them (dynamically). Is it possible to have a variable-depth, multi-relationship MATCH that I envisage?
Thanks!
Let me restate what I believe is being asked.
"If there is a path of the form (a)-[:X]->(b), find all other paths from a to b."
The answer is simple:
MATCH p=(a)-[:X]->(b), q=(a)-[r*]->(b)
WHERE p<>q
RETURN r;