With the following query I've almost achieved what I want in terms of the structure:
SELECT
t.id,
t.name,
json_agg(places) AS places
FROM
trips t
-- trips_cities
INNER JOIN (
SELECT
tc.city_id,
tc.trip_id,
json_agg(json_build_object(
'city_id', tc.city_id,
'airports', airports
)) AS places
FROM
trips_cities tc
-- airports
LEFT JOIN (
SELECT
a.id,
a.country_id,
json_agg(json_build_object(
'airport_id', a.id
)) AS airports
FROM airports a
GROUP BY a.id
) a ON a.id = ANY(tc.airport_ids)
-- /airports
GROUP BY 1, 2
) tc ON tc.trip_id = t.id
-- /trips_cities
GROUP BY 1
However instead of airports being an array, it returns duplicate cities:
[
[
{
"city_id": 20,
"airports": [
{
"airport_id": 2
}
]
},
{
"city_id": 20,
"airports": [
{
"airport_id": 1
}
]
}
]
]
Instead of how I'd like it to be, which I can't seem to figure out the grouping for:
[
[
{
"city_id": 20,
"airports": [
{
"airport_id": 2
},
{
"airport_id": 1
}
]
}
]
]
Some data:
INSERT INTO trips (id, name)
VALUES (1, 'My First Trip'),
(2, 'My Second Trip');
INSERT INTO trips_cities (trip_id, city_id, airport_ids)
VALUES (1, 'London', {1,2}),
(2, 'Paris', {1}),
(3, 'Berlin', {2});
INSERT INTO airports(id, name)
VALUES (1, 'Heathrow'),
(2, 'Gatwick');
Table structures are as follows:
trips
id
trips_cities
trip_idcity_idairport_ids[]
airports
id
In summary:
- For each trip join
trips_cities - For each
trips_citiesjoin allairports - Create a nested agg of the results as in my final JSON example above