Reputation: 264
I have a neo4j graphdb that stores ordered collections of nodes (let's say Person nodes), and each of those people has a Talent node:
(p:Person)-[:HAS_TALENT]->(t:Talent)
I'm organizing a talent show, and have the schedule of the order in which people are going to perform:
(p:Person)-[:FOLLOWS*]->(q:Person)
I can write a query to return a path that represents the order in which the people perform, and when I return that path, the Person nodes show up in the order that they appear in the path. However, when I do a sub-query to return the talents that the people are performing, they no longer show up ordered by the path.
Is there a way to order nodes based on the order they appear in a path? I've tried using COLLECT
to get a list of Person nodes, but I can't seem to find a way to use that collection to get back an ordered list of Talent nodes.
My current path-query looks something like this, with a special start and end node so I know who's first and last. (I don't have the DB in front of me right now, so apologies if it's not spot-on):
MATCH p=(s:StartNode {side:"start"})-[:FOLLOWS*1..10]->(s:StartNode {side:"end"})
RETURN p
I've run through a lot of different options for retrieving the path from start to finish, and they have their pros and cons, but I can't find a way to retrieve the Talent nodes in the same order.
EDIT: It seems I may have over simplified my example scenario. The database I'm actually working with has multiple paths from start to finish through Person nodes, and I have a query to first select just a single path from start to finish before moving ahead to match Talent nodes. Apologies to @Dirk Horsten who answered the question I asked, but not the one I needed answered.
Since I'm editing this already, @Dave Bennett 's answer solved my problem because the unwind
function seems to keep the path's order intact for future MATCH clauses.
Upvotes: 2
Views: 4342
Reputation: 11216
Assume that the performers are Person 1..5 and they each possess a single talent A..E such that Person 1
has Talent A
and Person 5
has Talent E
. And the talent show start with Person 1 and ends with Person 5.
//match all of the possible show paths where the show starts
// with the first performer
MATCH show=(:Person {name:'Person 1'})<-[:FOLLOWS*]-(:Person)
// pass on the performers and the number of performers
// as identifiers with the WITH clause
WITH nodes(show) AS performers, length(show) AS num
// order the possible shows in descending order by number of performers
ORDER BY num DESC
// limit the list to the show with the most performances
LIMIT 1
// unwind the performers collection as individual performer
UNWIND performers AS p
// match the talent that matches the performers
MATCH p-[:HAS_TALENT]->(t:Talent)
// return the name of the performer and their talent
RETURN p.name, t.name
Upvotes: 4
Reputation: 3845
If I add a (show) node in front
create (s:show{date:'2014-01-31'})
create (s)<-[:STARTS]-(p1:person{pId:1})-[:HAS_TALENT]->(:talent{tId:1})
create (p1)<-[:FOLLOWS]-(p2:person{pId:2})-[:HAS_TALENT]->(:talent{tId:2})
create (p2)<-[:FOLLOWS]-(p3:person{pId:3})-[:HAS_TALENT]->(:talent{tId:3})
create (p3)<-[:FOLLOWS]-(p4:person{pId:4})-[:HAS_TALENT]->(:talent{tId:4})
create (p4)<-[:FOLLOWS]-(p5:person{pId:5})-[:HAS_TALENT]->(:talent{tId:5})
Then this should do the job:
match spt=(s:show{date:'2014-01-31'})<-[:STARTS|FOLLOWS *]-(p:person)-[:HAS_TALENT]->(t:talent)
return p.id as performer,t.tId as act order by length(spt)
Of cource you can as well return the full t
, you can collect(t.tId)
or whatever you like
(To be tested on a PC with Neo4j)
Upvotes: 1