Reputation: 113
First, here is what I desire and I then will explain what I have tried.
In this simplified example I have a graph with nodes A
, B
, C
, and D
. I have relationships like A->B
, B->C
and B->D
only. I would like to aggregate each of the connections to a node A into a list and subsequently each of the connections to node B into two separate lists: one for B->C
connections and one for B->D
connections. Something like the below.
{
'A': 'A',
'Bs': [{
'B': 'B',
'Cs': [
...
]
'Ds': [
...
]
}, ...]
}
Now for my specific use case. I have trip nodes that are connected to waypoints. Waypoints are connected to airports and what I call a POI. I would like to return a trip with a list of its waypoints where each waypoint has two lists: a list of airports and a list of POI. I have not been able to accomplish this successfully and have not found any examples with this exact use case. In addition to the query below, I have tried many other variations with foreach loops and other constructs. I think this is the closest I have come. In the below query, B->C
would equate to the HAS_AIRPORTS
relationship and B->D
to the HAS_POI
relationship. I think my problem comes down to there being multiple aggregations that need to be made on the same level. I am getting some strange output where things seem to be repeating themselves because of the 2 aggregations. Sorry if this is not clear, I am new to the terminology of the cypher query language. Thank you, I am appreciative of any help.
MATCH (t:Trip {uid: $tripId})
WITH t
OPTIONAL MATCH (t)-[:HAS_WAYPOINTS]-(w {active: true})
WITH t, w
OPTIONAL MATCH (w)-[wa:HAS_AIRPORT]-(a:NeoAirport)
WITH t, w, collect(a{.*, active:wa.active}) as airports
WITH t, w {.*, airports:airports } as waypoints
OPTIONAL MATCH (w)-[wp:HAS_POI {active: true}]-(p:PointOfInterest)
WITH t, waypoints, w, collect({source:wp.source, uid:p.uid, placeId:p.placeId}) as pois
WITH t, apoc.map.setKey( waypoints, 'pointsOfInterest', pois )
WITH t, t {.*, waypoints: collect(waypoints) } as trips
OPTIONAL MATCH (t)-[tsa:HAS_START_AIRPORTS]-(sa)
WITH t, collect(sa) as sa, trips
WITH t, apoc.map.setKey( trips, 'startAirports', sa ) as trips
OPTIONAL MATCH (t)-[tea:HAS_START_AIRPORTS]-(ea)
WITH t, collect(ea) as ea, trips
WITH t, apoc.map.setKey( trips, 'endAirports', ea ) as trips
RETURN trips
Upvotes: 0
Views: 949
Reputation: 30397
One thing that will help is that aggregations are not the only way to get the result from matched patterns into a list. You can use pattern comprehensions instead, which may simplify your query.
Also I'm going to assume that there is a :HAS_END_AIRPORTS relationship to end airports of a trip, and that we should use that to get end airports.
MATCH (t:Trip {uid: $tripId})
OPTIONAL MATCH (t)-[:HAS_WAYPOINTS]-(w {active: true})
WITH t, w,
[(w)-[wa:HAS_AIRPORT]-(a:NeoAirport) | a {.*, active:wa.active}] as airports,
[(w)-[wp:HAS_POI {active: true}]-(p:PointOfInterest) | p {source:wp.source, .uid, .placeId}] as pointsOfInterest
WITH t, collect(w {.*, airports, pointsOfInterest}) as waypoints
WITH t, waypoints,
[(t)-[:HAS_START_AIRPORTS]-(sa) | sa] as startAirports,
[(t)-[:HAS_END_AIRPORTS]-(ea) | ea] as endAirports
RETURN t {.*, waypoints, startAirports, endAirports} as trips
Upvotes: 1