Создание многопоточной системы личных сообщений, такой как Facebook и Gmail. - PullRequest
31 голосов
/ 21 июня 2011

Я создаю систему многопоточных сообщений, очень похожую на gmail и facebook, в которой в папке «Входящие» перечисляются самые последние темы, отображающие тему, имя отправителя и отметку времени самого последнего сообщения.

Вот как настраиваются мои таблицы:

users:
    user_id
    user_name

thread:
    thread_id
    title
    to_id
    to_keep
    to_read
    from_id
    from_keep
    date

message:
    message_id
    thread_id
    to_id
    from_id
    message_text
    date

Сейчас я делаю то, что когда пользователь создает новое сообщение, он создает новый поток в таблице потоков, а затемновое сообщение в таблице сообщений, и если пользователь отвечает на поток, он дублирует текущий поток в таблице потоков, за исключением того, что меняет местами to_id и from_id, а затем создает новое сообщение на основе этого.

Кроме того, для представления входящих сообщений я могу просто запросить все темы, основываясь на user_id.что-то вроде SELECT * FROM thread WHERE to_id = 2 and to_keep = TRUE ORDER BY date DESC или если я хочу просмотреть сообщения в папке исходящих сообщений, это будет что-то вроде SELECT * FROM thread WHERE from_id = 2 and from_keep = TRUE ORDER BY date DESC.

Если пользователь открывает поток, когда появляется новое сообщение, то to_read обновляется до true UPDATE thread SET to_read = TRUE WHERE thread_id = 4.

Мне кажется, что я слишком усложнил этот процесс и что должен быть лучший способ сделать это.

Буду признателен за любую помощь или идеи.

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

1 Ответ

45 голосов
/ 21 июня 2011

Почему бы вам не отделить взаимосвязи между сообщениями и просмотром пользователем каждого сообщения?

Я бы сделал потоковую обработку с помощью самообращающихся ссылок на сообщение.Другими словами, в сообщении есть столбец «responseding_to_message_id».

Я не уверен, что понимаю, почему у вас "to_id".Направлены ли сообщения отдельным пользователям?Это кажется очень ограниченным.Я бы подумал, что у вас либо не будет получателя (то есть получатель - это доска объявлений, которую может прочитать каждый), либо у вас будет возможность указать несколько получателей, как в случае электронной почты.Возможно, вы сможете объяснить больше о том, как должна использоваться система.

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

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

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

РЕДАКТИРОВАТЬ: Эскиз ERD:

Вот быстрый набросоко чем я говорю ...

ERD Sketch

Независимо от того, выбрал ли отправитель сохранение сообщения, он помечен в самом сообщении.Если сообщение является началом нового потока, столбец reply_to_message_id имеет значение NULL, в противном случае это message_id родительского сообщения.Может быть несколько получателей, каждый из которых имеет свою собственную возможность сохранять сообщение или нет, а также возможность отслеживать дату и время, когда получатель читает сообщение.

РЕДАКТИРОВАТЬ 2:Альтернативный ERD и запрос самого последнего сообщения

@ OP спросил, как запросить самое последнее сообщение в цепочке.Ответ зависит от формы потока.У вас может быть либо плоский поток, в котором каждое сообщение идет до конца линейного потока сообщений, либо у вас может быть поток в форме дерева, где у каждого сообщения есть определенный родительский элемент, если только он не является корнем потока.В приведенной выше ERD поле response_to_message_id может использоваться в любом случае.Если нить плоская, то FK всегда находится в корневом СООБЩЕНИИ.Если поток имеет древовидную форму, то FK является непосредственным родителем ответа MESSAGE.

Если типичный запрос, который вы хотите выполнить, это «какое последнее сообщение в ветке?»и ваши потоки плоские, тогда вы можете использовать SQL следующим образом:

select top 1
  M.message_id
, M.sent_datetime
, M.title
, M.message_text
, S.user_id
, S.user_name
-- and anything else you want...
from MESSAGE M inner join USER S
  on M.sender_user_id = U.user_id
where M.reply_to_message_id = @ThreadRootMessageID
order by
  M.sent_datetime desc

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

Tree Thread ERD

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

Если вы используете эту ERD, тогда запрос «самое последнее сообщение в потоке X» будет таким же, как и выше, но с M.thread_root_message_id в предложении where вместо M.reply_to_message_id.

...