Многие ко многим таблицам объединяются в массивы - PullRequest
1 голос
/ 16 марта 2019

Как я могу ВЫБРАТЬ книгу в этом формате:

{
   title: 'Avengers', 
   description:'Good book', 
   tags: [{id:1, name: 'Drama'},{id:2, name: 'Horror'}]
   authors: [{id:1, name: 'Alex'},{id:2, name: 'Tanya'}]
}

для таблиц с отношением "многие ко многим":

Или, может быть, лучше сделать 3 разных pool.requests?

книг

|id|title     |description|
|1 |'Avengers'|'Good book'|
|2 |'Fear'    |'Scary'

авторов

|id|name
|1 |'Alex'
|2 |'Tanya'

авторы_ книг

|book_id|author_id
|1      |1
|1      |2
|2      |1

теги

|id|name
|1 |'Drama'
|2 |'Horror'

тегов_бук

|book_id|tag_id
|1      |1
|1      |2
|2      |1

Я использовал это раньше без таблицы авторов:

SELECT b.title, b.id, b.description,
 json_agg(json_build_object('id', t.id, 'name', t.name, 'description', 
 t.description, 'likes', tb.likes) ORDER BY tb.likes DESC) AS tags
 FROM books AS b
 INNER JOIN tags_books AS tb ON (b.id = tb.book_id)
 INNER JOIN tags AS t ON (tb.tag_id = t.id)
 WHERE b.id = $1
 GROUP BY b.id;`

Но с новым INNER JOIN для авторов таблиц появятся повторяющиеся значения.

1 Ответ

1 голос
/ 16 марта 2019

Вы должны агрегировать данные (authors и tags) в отдельных производных таблицах (подзапросах в предложении FROM):

select 
    b.title, 
    b.description,
    t.tags, 
    a.authors
from books as b
join (
    select 
        tb.book_id,
        json_agg(json_build_object('id', t.id, 'name', t.name) order by tb.likes desc) as tags
    from tags_books as tb
    join tags as t on tb.tag_id = t.id
    group by tb.book_id
    ) t on b.id = t.book_id
join (
    select 
        ab.book_id,
        json_agg(json_build_object('id', a.id, 'name', a.name) order by ab.author_id) as authors
    from authors_books as ab
    join authors as a on ab.author_id = a.id
    group by ab.book_id
    ) a on b.id = a.book_id

  title   | description |                             tags                              |                           authors                           
----------+-------------+---------------------------------------------------------------+-------------------------------------------------------------
 Avengers | Good book   | [{"id" : 2, "name" : "Horror"}, {"id" : 1, "name" : "Drama"}] | [{"id" : 1, "name" : "Alex"}, {"id" : 2, "name" : "Tanya"}]
 Fear     | Scary       | [{"id" : 1, "name" : "Drama"}]                                | [{"id" : 1, "name" : "Alex"}]
(2 rows)
...