rzajac
rzajac

Reputation: 1601

Find shortest path between nodes with additional filter

I'm trying to model flights between airports on certain dates. So far my test graph looks like this:

graph

Finding shortest path between for example LTN and WAW is trivial with:

MATCH (f:Airport {code: "LTN"}), (t:Airport {code: "WAW"}), 
p = shortestPath((f)-[]-(t)) RETURN p

Which gives me:

enter image description here

But I have no idea how to get only paths with Flights that have relation FLIES_ON with given Date.

Link to Neo4j console

Upvotes: 9

Views: 7123

Answers (3)

Nicole White
Nicole White

Reputation: 7790

Here's what I would do with your given model. The other commenters' queries don't seem right, as they use ANY() instead of ALL(). You specifically said you only want paths where all Flight nodes on the path are attached to a given Date node with a :FLIES_ON relationship:

MATCH (LTN:Airport {code:"LTN"}),
      (WAW:Airport {code:"WAW"}), 
      p =(LTN)-[:ROUTE*]-(WAW)
WHERE ALL(x IN FILTER(x IN NODES(p) WHERE x:Flight) 
          WHERE (x)<-[:FLIES_ON]-(:Date {date:"130114"}))
WITH p ORDER BY LENGTH(p) LIMIT 1
RETURN p

http://console.neo4j.org/r/xgz84y

Upvotes: 4

Christophe Willemsen
Christophe Willemsen

Reputation: 20175

The problem is that using shortestPath or allShortestPaths will never include the Date nodes.

What you need to do is to filter the pattern with the date node (I don't know however how you store the date, so I'll take Ymd format:

MATCH (f:Airport {code: "LTN"}), (t:Airport {code: "WAW"})
MATCH p=(f)-[*]-(t)
WHERE ANY (r in rels(p) WHERE type(r) = 'FLIES_ON')
AND ANY (n in nodes(p) WHERE 'Date' IN labels(n) AND n.date = 20150120)
RETURN p
ORDER BY length(p)
LIMIT 1

Another solution and less costly, is to include the date in your match and building yourself the path with it :

MATCH (n:Date {date:20150120})
MATCH (f:Airport {code:"LTN"}), (t:Airport {code:"WAW"})
MATCH p=(f)<-[*]-(n)-[*]->(t)
RETURN distinct(p)
ORDER BY length(p) 

Upvotes: 0

cechode
cechode

Reputation: 1022

though this would not be my preferred structure for this kind of data; in answering your question i might go this way instead. get the paths, filter the path and get the first one ordered by length.

in the console tests is runs faster than the one suggested above as the query plan is simpler.

Anyhoo i hope this at least points you in a good direction :)

MATCH (f:Airport { cd: "ltn" }),(t:Airport { cd: "waw" }), p =((f)-[r*]-(t))
WHERE ANY (x IN relationships(p) 
           WHERE type(x)='FLIES_ON') AND ANY (x IN nodes(p) 
                                              WHERE x.cd='130114')
RETURN p
ORDER BY length(p)
LIMIT 1

Upvotes: 0

Related Questions