skip to Main Content

I am using FalkorDb 4.0.5 which is a fork of the now discontinued Redis Graph.

My simplified test case:

GRAPH.QUERY g 

// Create 4 nodes:
"CREATE (w:Work{name:'Work'}), (a:City{name:'A'}), (b:City{name:'B'}), (c:City{name:'C'}),

// Create "Road" edges, each with an `x` property: 
(w)-[r0:Road{x:0}]->(a), (a)-[r1:Road{x:1}]->(b), (b)-[r2:Road{x:2}]->(c), 

// Add "Accom" edges, also with an `x` property:
(a)-[a1:Accom{x:10}]->(h1:Hotel{name:'Hilton'}), 
(a)-[a2:Accom{x:11}]->(h2:Hotel{name:'Marriot'}), 
(c)-[a3:Accom{x:12}]->(h3:Hotel{name:'Marriot'}) 

RETURN w,a,b,c,r0,r1,r2,a1,h1,a2,h2,a3,h3"

This results in a graph that looks like this with the x values on each edge shown:
enter image description here

So, the x in the path looks like:

(Work)-[x:0]-(A)-[x:1]-(B)-[x:2]-(C)

I am trying to work out how to write a query so I get 2 paths (because City A has 2 Accom edges: Hilton and Marriot) that looks like the following schematic.

for Hilton:  (Work)-[x:10]-(A)-[x:1]-(B)-[x:2 ]-(C)
for Marriot: (Work)-[x:11]-(A)-[x:1]-(B)-[x:12]-(C)

{repeat for other Hotels found attached to A ...}

i.e: Make a path from Work to C for each Hotel found attached to A (Hilton and Marriot in this case, but could be many others). Each path needs to be updated to reflect the x found on the Accom edge where that same Hotel is attached to the Town.

This is the query for the path for just the Road edges:

GRAPH.QUERY g "MATCH path=(p)-[r:Road*]->(c) RETURN path"

which yields the (Work)-[x:0]-(A)-[x:1]-(B)-[x:2]-(C).

But what query to get the two paths listed above?

Edit: Maybe I just need to do the following to get all the data then work it out in my application (Java / Quarkus)

GRAPH.QUERY g "MATCH path=(p)-[r]->(c) RETURN path"

Yields:
1) 1) "[(0), [0], (1)]"
2) 1) "[(1), [1], (2)]"
3) 1) "[(1), [3], (4)]"
4) 1) "[(1), [4], (5)]"
5) 1) "[(2), [2], (3)]"
6) 1) "[(3), [5], (6)]"

Thanks!

2

Answers


  1. Chosen as BEST ANSWER

    @SWilly22: Thanks for your suggestion and thanks for your work on FalkorDB. :-) I learned a few things from your suggestion.

    As I was working through this I realised that the outcome I was trying to achieve was not what I needed in my app. So, the original question about dynamically creating the paths as described in the question has been replaced by a different desired outcome.

    What I needed was a record for each Hotel attached to City A returning the x properties from the Accom relationships where a City had the Hotel in question, with the list of cities in the same order as in the graph.

    My desired output now looks like:

      1) 1) "Marriot"
         2) "[{city: A, x: 11}, {city: C, x: 12}]"
      2) 1) "Hilton"
         2) "[{city: A, x: 10}]"
    

    The query follows. There is probably a better way to do this but it works! And yes, in the final version I will use parameter substitution for the start and end Cities :-)

    GRAPH.QUERY g "
    MATCH (a:City{name:'A'})-[:Accom]->(h:Hotel) WITH h.name AS hotelName 
    MATCH path=(w:Work)-[:Road*]->(c:City{name:'C'}) 
    UNWIND relationships(path) as uwpath 
    UNWIND startNode(uwpath) as n 
    CALL { WITH n, hotelName 
       MATCH (c:City)-[r:Accom]->(h:Hotel{name:hotelName}) RETURN c.name as city, r.x as x 
    } 
    WITH hotelName, collect( DISTINCT {city: city, x: x}) as records 
    RETURN hotelName, records"
    

    Here is the same query with comments:

    GRAPH.QUERY g "
    
    // Get the Hotel names attached to City A
    MATCH (a:City{name:'A'})-[:Accom]->(h:Hotel) WITH h.name AS hotelName
     
    // Get the path from Work to City C using the Road relationship
    MATCH path=(w:Work)-[:Road*]->(c:City{name:'C'}) 
    
    // Unwind the path into path records
    UNWIND relationships(path) as uwpath 
    
    // Unwind the path record to get the startNode as n
    UNWIND startNode(uwpath) as n 
    
    // Make a sub query call passing in the node and the hotelName
    CALL { WITH n, hotelName 
    
      // See if this City has that Hotel and return the City name and the Accom.x property
      MATCH (c:City)-[r:Accom]->(h:Hotel{name:hotelName}) RETURN c.name as city, r.x as x 
    } 
    
    // Collect the result of the sub query into records of City and x
    // Use DISTINCT to avoid duplicates as a result of the iteration of the CALL
    WITH hotelName, collect( DISTINCT {city: city, x: x}) as records 
    
    // Return the hotel name and the Cities and x having that Hotel
    RETURN hotelName, records"
    

    I am not sure if there is a better way to avoid needing DISTINCT, or even if there is a better way to achieve this outcome, but for now this works.

    Thanks, Murray


  2. What about:

    MATCH p = (w:Work)-[:Road]->(A:City)-[:Accom]->(h:Hotel)<-[:Accom]-(A)-[:Road*]->(c:City{name:'C'}) RETURN p
    

    Although it might be a bit too specific, as it requires the Hotel node to be directly connected to the first City reachable from Work.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search