I know this may be a simple question but I'm having a hard time finding an answer.
I want to find all "Persons" who have INTERESTED_IN the same Activities as a Person with the id of 1 that is not FRIENDS_WITH person 1
Something like
MATCH (p:Person {Id:1})--[r:INTERSTED_IN]-->(a:Activity {name:Skiing})<--(f:Person)
RETURN f.name
Might be wrong..
I think this will find everyone with the same relationship but then I want to make sure they aren't already friends.
Trying to figure out cypher and can't find any good examples of this.
Almost got it!
MATCH (p:Person { id: 1 })-[r:INTERESTED_IN]->(a:Activity { name: 'Skiing' })<-[r2:INTERESTED_IN]-(f:Person)
WHERE NOT (p)-[:FRIENDS_WITH]-(f)
RETURN f.name
Note that id here is a property, and not the internal node ID. If that's what you're looking for, you'd do this:
MATCH (p:Person)-[r:INTERESTED_IN]->(a:Activity { name: 'Skiing' })<-[r2:INTERESTED_IN]-(f:Person)
WHERE ID(p) = 1 AND NOT (p)-[:FRIENDS_WITH]-(f)
RETURN f.name
And it's "cypher." ;-)
Related
I am running a query to find the path from a user to a permission node in neo4j and I want to make sure it doesn't traverse some relationships. Therefore I've used the following cypher :
PROFILE
MATCH path = (u:user { _id: 'ea6b17e0-3b9e-11ea-b206-e7610aa23593' })-[r:accessRole|isMemberOf*1..5]->(n:PermissionSet { name: 'project'})
WHERE all(x IN r WHERE NOT (:PermissionSet)-[x]->(:user))
RETURN path
I didn't expect the where clause to trigger so many hits. I believe I'm not writing my test correctly.
(2000 nodes/ 3500 rels => 350,000 hits for "(:PermissionSet)-[x]->(:user)"
any advice?
Not sure this is the correct answer, but I added a WITH statement
PROFILE
MATCH path = (u:user { _id: 'ea6b17e0-3b9e-11ea-b206-e7610aa23593' })-[r:accessRole|isMemberOf*1..5]->(n:PermissionSet { name: 'project'})
WITH path,r
WHERE all(x IN r WHERE NOT (:PermissionSet)-[x]->(:user))
RETURN path
And the dbhits for "(:PermissionSet)-[x]->(:user)" went down to 2800 hits.
I can guess why it does that, but I'd love some more experts explanations, and is there a better way to do it? (this way is fine with me performance-wise)
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
Apparently it seems like the following WHERE clause will not work because we have two relationships (WorksAt and ResponsibleFor) in our query. If there was only one relationship then this would work like magic. Here in the query below the query returns all the courses in teh department science but it does not filter out courses NOT taught by Maria Smith. All i want to do is get only the courses taught by Maria Smith who works in Science Department.
I came across WITH and Start Clause that seem to be potential candidate clauses make it work where you could filter out one part of the query before sending it to another.
http://neo4j.com/docs/stable/query-with.html
but i havent been able to grasp the concept yet. Anyone up for help?
MATCH (d:Department)<-[w:WorksAt]-(t:Tutor)-[r:ResponsibleFor]->(c:Courses)
WHERE d.name='Science'
AND t.name='Maria Smith'
return c,r
There are a number of ways to skin this particular cat. Let's break it down.
Find the tutor whose name is 'Maria Smith' that works in the 'Science' department
MATCH (d:Department)<-[:WorksAt]-(t:Tutor)
WHERE d.name = 'Science' AND t.name = 'Maria Smith'
RETURN t
Find the courses that a tutor teaches
MATCH (t:Tutor)-[:ResponsibleFor]->(c:Courses)
RETURN t.name, c
Bring these two together to get the courses that Maria Smith from the Scence department teaches
MATCH (d:Department)<-[:WorksAt]-(t:Tutor)
WHERE d.name = 'Science' AND t.name = 'Maria Smith'
WITH t
MATCH (t)-[r:ResponsibleFor]->(c:Courses)
RETURN t.name, r, c
This can also be written as
MATCH (d:Department { name : 'Science' })<-[:WorksAt]-(t:Tutor { name : 'Maria Smith' })
WITH t
MATCH (t)-[r:ResponsibleFor]->(c:Courses)
RETURN t.name, r, c
To maximise query performance you can use schema indexes to quickly locate your Department and Tutor nodes. Are you doing this? To create the indexes use
CREATE INDEX ON :Department(name)
CREATE INDEX ON :Tutor(name)
Run these lines separately.
As an aside were you to want to list the courses that each tutor taught, as suggested above in the second query, you could use the following query to aggregate the courses for each tutor.
MATCH (t:Tutor)-[:ResponsibleFor]->(c:Courses)
RETURN t.name as CourseTutor, collect(c.name) as CourseName
Hope this helps.
Nice breakdown. For performance details on this type of query, refer to Wes Freeman's Pragmatic Cypher Optimization. In setting up the match, start with the smaller node set and work toward the larger (Wes's Rule 4).
I am trying to write a query which returns only the first common node between two nodes in a scenario where there may be multiple.
Using this graph for reference - http://neo4j.com/docs/stable/cypher-cookbook-friend-finding.html.
For example, I'm Joe, and I would like to find the list of friend-of-friends I don't know, with only one person that I should ask for an introduction. An example return set is this, even though Bill is also a connection to Ian:
Bill Derrick
Sara Ian
Sara Jill
I've tried using DISTINCT, but that doesn't group properly:
MATCH (joe { name: 'Joe' })-[:knows]-(friend)-[:knows]-(friend_of_friend)
WHERE NOT (joe)-[:knows]-(friend_of_friend)
WITH DISTINCT friend_of_friend, friend
RETURN friend.name, friend_of_friend.name
I'm starting to believe I need a second query with the friend node passed to it. Hopefully not though, because that sounds painfully inefficient. What am I missing?
You need to do an aggregation on level of friend using the collect function:
MATCH (joe { name: 'Joe' })-[:knows]-(friend)-[:knows]-(friend_of_friend)
WHERE NOT (joe)-[:knows]-(friend_of_friend)
RETURN friend.name, collect(friend_of_friend.name)
update
MATCH path=(joe { name: 'Joe' })-[:knows]-(friend)-[:knows]-(friend_of_friend)
WHERE NOT (joe)-[:knows]-(friend_of_friend)
RETURN collect(friend)[0] AS friend, friend_of_friend
This gives you 3 rows:
Bill, Derrick
Bill, Ian or Sara, Ian
Sara, Jill
Here it's not deterministic if Bill-Ian or Sara-Ian is in the result.
I am doing some research into Graph Database Systems as part of POC to possibly move a system across to. I am really new to the concept and come from a RDBMS background.
I have a model (schema?) that looks like:
Person-[HAS_NAME {type:First|Middle|Last}]-Name
Person-[WAS_BORN_ON]-DateOfBirth
Person-[RESIDES_AT {type:Current|Previous}]-Address
I am able to store this data perfectly using Neo4J and Neo4JClient in a C# application.
Where I am falling flat on my backside is that I want to get out of the store, a list of People and all nodes that are connected to the person (eg their Names, DateOfBirth and Addresses) where certain conditions are met,
I have started with this:
MATCH (dob:DateOfBirth)-[WAS_BORN_ON]-(person:Person)-[HAS_NAME]-(name:Name) WHERE dob.Id = '1954-05-09' RETURN person, dob, name
And it produces something like this which is great:
But I want to restrict it to people that have a (last) name of "williams" so I go with this
MATCH (dob:DateOfBirth)-[WAS_BORN_ON]-(person:Person)-[HAS_NAME]-(name:Name) WHERE dob.Id = '1954-05-09' and name.Value = 'Williams' RETURN person, dob, name"
Unfortunately it removes all the other names:
Unfortunately I want this:
Maybe something like this would work?
MATCH (dob:DateOfBirth{Id: "1954-05-09"})<-[:WAS_BORN_ON]-(person:Person)
WITH dob, person
MATCH (person)-[:HAS_NAME]->(surname:Name{Value: "Williams"})
WITH person, dob
MATCH (person)-[:HAS_NAME]->(name:Name)
RETURN person, dob, name
Edit: Updated query to improve performance as suggested by ulkas.
I would have gone the easy route...
match (dob:DateOfBirth{Id: "1954-05-09"})--(p:Person)--(surname:Name{Value: "Williams"})
optional match (p)--(n:Name)
return dob, p, n
alternatively with a WHERE clause:
match (dob:DateOfBirth)--(p:Person)--(surname:Name)
optional match (p)--(n:Name)
where dob.Id = "1954-05-09" and surname.Value = "Williams"
return dob, p, n
But then again, I'm not the expert on performance; I focus first on simplicity.