I have a problem with a query to select some data from my database,
My database has 3 tables: movies, actors, movies_actors.
ACTORS TABLE
+-----------+
| ID | NAME |
+-----------+
| 1 | Bob |
+-----------+
| 2 | John |
+-----------+
MOVIES TABLE
+-----------+
| ID | TITLE|
+-----------+
| 1 | aaa |
+-----------+
| 2 | bbb |
+-----------+
MOVIES-ACTORS TABLE (MANY-TO-MANY)
+--------------------+
| MOVIE_ID| ACTOR_ID |
+--------------------+
| 1 | 1 |
+--------------------+
| 1 | 2 |
+--------------------+
| 2 | 1 |
+--------------------+
I need to get all the movies, and inside every movie i need to have a property called actors, that should be an array containing all the actors that are related to that movie.
the response should look something like this:
[
{id: 1, title: "aaa", actors: [{id: 1, name: "Bob"}, {id: 2, name: "John"}]},
{id: 2, title: "bbb", actors: [{id: 1, name: "Bob"}]}
]
What is the best way to achieve this result? I’m able to do this with 2 different requests and mapping and filtering the results, but it doesn’t seem right to me. So i tried to write a single query using JOIN but i was only able to get a "movie" row for every actor in it.
I will share it because i think it’s not far from the solution.
SELECT movies.*, json_build_object('name', actor.name, 'id', actor.id) AS actors
FROM movies
LEFT OUTER JOIN movies_actors
ON movies.id = movies_actors.movie_id
LEFT OUTER JOIN actors
ON movies_actors.actor_id = actors.id
and this is what I’m getting back so far:
[
{id: 1, title: "aaa", actors: {id: 1, name: "Bob"}},
{id: 1, title: "aaa", actors: {id: 2, name: "John"}},
{id: 2, title: "bbb", actors: {id: 1, name: "Bob"}}
]
3
Answers
You need to
GROUP BY
themovies.id
(I assume it’s a primary key) and usejson_agg
to build your actors object:Output (for your sample data):
Demo on db-fiddle
So far so good, what you need to add as extra is
JSON_AGG()
function along with aGROUP BY
expression such asDemo
"Knit" the JSON structure trivially step by step, inside out first aggregate actors’ id/name pairs list (
ti
) then aggregate movies with their actors lists (tx
).