Определите, есть ли у 2 пользователей личный чат - PullRequest
2 голосов
/ 16 марта 2020

У меня есть следующая схема базы данных для простого приложения чата (упрощенно):

## users table
id

## chats table
id, type

## chat_user
chat_id, user_id

Проблема, которую я хочу решить, состоит в том, что, учитывая, что у меня есть 2 пользователя, как я могу получить запись chat для данного type данного я знаю, что этот спецификатор c chat type должен существовать только один раз, если он уже существует?

Например, у нас есть bob (id: 1) и Джеймс (id: 2) . bob инициирует чат с james :

insert into chats (type) values ('private') returning id;
-- returned ID is: 1234

insert into chat_user (chat_id, user_id) values (1234, 1);
insert into chat_user (chat_id, user_id) values (1234, 2);

Теперь я хочу запрос, который выдаст строку chat с идентификатором 1234, если я дам это 2 пользователя.

одно решение, которое я нашел для этого, - найти пересекающийся chat_id для этих 2 пользователей, и, поскольку я знаю, что для этих 2 пользователей существует только 1 private чат, я просто беру первый результат:

select * from chats where id in (
  select chat_id from chat_user where user_id = 1 and chat_id in (
    select chat_id from chat_user where user_id = 2
  )
) and type = 'private' limit 1;

Теперь, пока это работает, мне интересно, является ли это лучшим решением для этого? Будет ли этот запрос все медленнее и медленнее, когда у пользователей будет больше чатов?

Если это имеет значение, я использую Postgres для этого приложения чата.

Ответы [ 2 ]

2 голосов
/ 16 марта 2020

Вы можете использовать INTERSECT:

select * from chats 
where type = 'private'
and id in (
  select chat_id from chat_user where user_id = 1 
  intersect
  select chat_id from chat_user where user_id = 2
)
limit 1;

Я не думаю, что LIMIT 1 необходим, если может быть возвращен максимум 1 результат. Или объедините таблицы, отфильтруйте, сгруппируйте по идентификатору и установите условие в предложении having:

select c.id 
from chats c inner join chat_user u
on u.chat_id = c.id
where c.type = 'private' and u.user_id in (1, 2) 
group by c.id
having count(*) = 2
0 голосов
/ 16 марта 2020

Может ли более двух пользователей находиться в приватном чате? Если это так, агрегация с having, вероятно, является лучшим подходом:

select c.id 
from chats c inner join
     chat_user cu
     on cu.chat_id = c.id
where c.type = 'private' 
group by c.id
having count(*) filter (where cu.user_id in (1, 2)) = 2;

Конечно, это работает только для двух пользователей. Он также обрабатывает и более общий случай.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...