Sammy1Am
Sammy1Am

Reputation: 264

Cypher Query to Return Nodes in Path Order

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

Answers (2)

Dave Bennett
Dave Bennett

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

Dirk Horsten
Dirk Horsten

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

Related Questions