Создайте объект JSON из родительского -> дочернего отношения без дублирования

Я хочу запросить базу данных, получить ВСЕ данные пользователя и отправить их на мой внешний интерфейс в объекте JSON (со многими уровнями вложенности).

например

{
 user_id: 1,
 username: james,
 messages: [
  {
   message_id: 'fewfef',
   message: 'lorum ipsum'
   ... : {
    ...
   }
  }
 ]
}

Пример схемы/данных:

--user table (parent)
CREATE TABLE userdata (
    user_id integer,
    username text
);

INSERT INTO userdata VALUES (1, 'james');

-- messages table (child) connected to user table
CREATE TABLE messages(
    message_id integer,
    fk_messages_userdata integer,
    message text
);

INSERT INTO messages VALUES (1, 1, 'hello');
INSERT INTO messages VALUES (2, 1, 'lorum ipsum');
INSERT INTO messages VALUES (3, 1, 'test123');

-- querying all data at once
SELECT u.username, m.message_id, m.message FROM userdata u
    INNER JOIN messages m
        ON u.user_id = m.fk_messages_userdata
WHERE u.user_id = '1';

Это выводит данные так:

username|message_id|message    |
--------+----------+-----------+
james   |         1|hello      |
james   |         2|lorum ipsum|
james   |         3|test123    |

Проблема в том, что имя пользователя повторяется для каждого сообщения. Для больших баз данных и большего количества уровней вложенности это приведет к тому, что будет запрашиваться/отправляться много бесполезных данных.

Лучше сделать один запрос, чтобы получить все эти данные и отправить их в серверную часть, или сделать отдельный запрос для каждой таблицы и получить только те данные, которые мне нужны?

Например, я мог бы запустить эти запросы:

-- getting only user metadata
SELECT username from userdata WHERE user_id = '1';
-- output
username|
--------+
james   |

-- getting only user's messages
SELECT m.message_id, m.message as message_id FROM userdata u
    INNER JOIN messages m
        ON u.user_id = m.fk_messages_userdata
WHERE u.user_id = '1';
--output
message_id|message_id |
----------+-----------+
         1|hello      |
         2|lorum ipsum|
         3|test123    |

Таким образом я получаю только те данные, которые мне нужны, и с ними немного проще работать, так как они более организованы. Но есть ли недостаток в выполнении отдельных запросов вместо одного большого? Есть ли другие способы сделать это?

Соединения могут создавать строки результатов с повторяющимися данными, когда задействованы отношения с множественностью :n. Если вы хотите избежать этого, не выполняйте такие соединения. Вместо этого запрашивайте каждую сторону отдельно. JSON достаточно хорошо подходит для представления результирующей многоуровневой структуры данных.

John Bollinger 27.11.2022 20:14
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
1
1
606
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Лучше сделать один запрос, чтобы получить все эти данные и отправить их в серверную часть, или сделать отдельный запрос для каждой таблицы и получить только те данные, которые мне нужны?

Лучше всего выполнить только один запрос и получить только нужные данные. Пока это не становится слишком сложным - что не IMO:

SELECT to_json(usr)
FROM  (
   SELECT u.user_id, u.username
       , (SELECT json_agg(msg)  -- aggregation in correlated subquery
          FROM  (
            SELECT m.message_id, m.message
            FROM   messages m
            WHERE  m.fk_messages_userdata = u.user_id
            ) msg
         ) AS messages
   FROM   userdata u
   WHERE  u.user_id = 1  -- provide user_id here once!
   ) usr;

рабочий пример

Есть много других способов.

(LEFT) JOIN LATERAL вместо коррелированного подзапроса. Видеть:

json_build_object() вместо преобразования целых строк из подзапросов. Видеть:

Но эта версия выше должна быть самой короткой и быстрой.

Связанный:

Другие вопросы по теме