I need to find out what publications have collaborated with a university.
I am new to neo4j, I'm not sure how to exactly go about it. I tried the query below, but this only returns records that are within that university only. I need to pull other universities that have collaborated.
This is what I have tried:
MATCH (f:FACULTY)-[p:PUBLISH]->(P:PUBLICATION),(f)<-[a:AFFILIATION_WITH]-(i:INSTITUION)
WHERE i.name = "UNIVERSITY_NAME"
RETURN i.name;
Also here is a description of the graph:
If I got your question right, you're almost there:
MATCH (i:INSTITUTION)<-[:AFFILIATION_WITH]-(:FACULTY)-[:PUBLISH]->(p:PUBLICATION)
WHERE i.name = "UNIVERSITY_NAME"
RETURN p.name;
Here, I am traversing the graph from an institution (university) down to the publication, through the faculty, and returning the name of the publication.
A couple of notes compared to your initial try:
The direction of the relationship Institution -> Faculty in your query does not match the one on your graph
You want to return publication names, not institutions
Related
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
Context:
I'm working on an Alumni project to understand the difference between giving and engagement. (engagement = showing up, attending events, volunteering, etc.) The value in the work will come from the insight gained from understanding the behavior partners.
In the query below I've been effective at bring back the "Biggest spenders", however I'd like to list the name of the (n) Alumni and the (a,b)gifts. There 30 gift types that fit into (a,b).
Please let me know your thoughts... Innosoljim
>//Who are Alumni that give the most?
>>MATCH (n:Alumni)-[r:Supportfin]->(b)
>>MATCH (n:Alumni)-[t:Gavefin]->(a)
>>RETURN n,b,a LIMIT 1500
Thanks for the Answer - Let me restate the goal for clarity: I'm trying to consolidate (into n.Alumni) many relationships -[Gave|Support]-> to unique nodes (Various Gifts) so that I can obtain a report on an Alumni's activity (giving, support, by n.name. The Graph model places the Alumni node at the center of each unique behavior (giving, support, graddate, address, degree, greeklife, etc....) Does this help?
MATCH (a:Alumni)-[r:Supportfin|Gavefin]->(gift)
RETURN a.name, collect(gift)
ORDER BY (a)-[r:Supportfin|Gavefin]-> count(*) DESC
Something like this maybe although this isn't working (syntaxerror)
Match Alumni to the gifts with both relationship types and return:
MATCH (a:Alumni)-[r:r:Supportfin|Gavefin]->(gift)
RETURN a.name, collect(gift)
Or split it by the different relationship types:
MATCH (a:Alumni)
OPTIONAL MATCH (s)-[:Supportfin]->(sup_gift)
OPTIONAL MATCH (a)-[:Gavefin]->(gave_gift)
RETURN a.name, collect(DISTINCT sup_gift), collect(DISTINCT gave_gift)
Without a proper decription of your graph model and problem the question is difficult to answer.
I am learning Cypher and have a problem that is likely an easy one for someone with more experience.
I created a small graph of authors and publications. The author is FROM a country, as in:
person -[:WROTE]-> book
person-[:FROM]-> country
Books have one or more authors. I want to find books that were co-authored by persons from more than one country. In other words, books that have international cooperation for their authorship.
Your advice would be a great help!
Assuming your labels are :Book, :Person, and :Country, and that :Persons can only be from one country:
// first find books written by more than one person
MATCH (b:Book)
WHERE SIZE((:Person)-[:WROTE]->(b)) > 1
WITH b
// now match on authors and their countries
MATCH (p:Person)-[:WROTE]->(b)
MATCH (p)-[:FROM]->(c:Country)
// associate books with the number of distinct author countries
// and filter to those with more than one
WITH b, COUNT(DISTINCT c) as authorCountries
WHERE authorCountries > 1
RETURN b
EDIT added more commentary below
This approach, using subqueries connected with WITH, lets you only expand out your graph (say, from persons to their countries) only on interested matches. In this case, it saves us from having to expand out and consider the larger graph of ALL books and their authors and their countries...we instead only do this with books that we know have more than one author.
If you do want to do the entire thing in one go, it would look something like this:
MATCH (b:Book)<-[:WROTE]-(:Person)-[:FROM]->(c:Country)
WITH b, COUNT(DISTINCT c) as authorCountries
WHERE authorCountries > 1
RETURN b
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 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.