Для построения такого JSON на SQL вам нужны функции
json_agg() /
json_build_object(), далее обычные запросы с объединениями и группировкой.
Пример как собрать JSON author
SELECT json_build_object(
'account_id', id,
'first_name', first_name,
'last_name', last_name
) AS author
FROM accounts
post собирается как
json_build_object(
'post_id', p.id,
'body', p.body,
'author', json_build_object(
'account_id', a.id,
'first_name', a.first_name,
'last_name', a.last_name
)
)
при объединении таблиц posts и accounts
через json_agg собираем в массив
SELECT json_agg(json_build_object(
'post_id', p.id,
'body', p.body,
'author', json_build_object(
'account_id', a.id,
'first_name', a.first_name,
'last_name', a.last_name
)
)) AS posts
FROM posts p
JOIN accounts a ON a.id = p.author_id
комментарии аналогично, но с группировкой по постам - post_id
SELECT json_agg(json_build_object(
'comment_id', c.id,
'body', c.body,
'author', json_build_object(
'account_id', a.id,
'first_name', a.first_name,
'last_name', a.last_name
)
)) AS comments
FROM comments c
JOIN accounts a ON a.id = c.author_id
GROUP BY post_id
далее объединяем комментарии с постами через post_id = id
для удобства комментарии вынес в CTE (общее табличное выражение)
WITH cmts AS (
SELECT json_agg(json_build_object(
'comment_id', c.id,
'body', c.body,
'author', json_build_object(
'account_id', a.id,
'first_name', a.first_name,
'last_name', a.last_name
)
)) AS comments,
post_id
FROM comments c
JOIN accounts a ON a.id = c.author_id
GROUP BY post_id
)
SELECT json_agg(json_build_object(
'post_id', p.id,
'body', p.body,
'author', json_build_object(
'account_id', a.id,
'first_name', a.first_name,
'last_name', a.last_name
),
'comments', COALESCE(c.comments, '[]')
)) AS "posts with comments"
FROM posts p
JOIN accounts a ON a.id = p.author_id
LEFT JOIN cmts c ON c.post_id = p.id
см. пример
sqlfiddle