Дизайн базы данных личных сообщений - PullRequest
11 голосов
/ 09 июня 2011

Хорошо, так что я думаю, что я достаточно близок к тому, чтобы получить то, что мне нужно, но я не уверен в нескольких вещах:

TABLE messages

message_id
message_type
sender_id
timestamp

TABLE message_type

message_type_code (1, 2, 3)
name (global, company, personal)

TABLE message_to_user

message_id
receiver_id
status (read/unread)

Цели:

  1. Возможность отправлять ГЛОБАЛЬНЫЕ сообщения всем пользователям.
  2. Отправка ПЕРСОНАЛЬНЫХ сообщений от 1 или более пользователей.
  3. Определите, было ли полученное сообщение прочитано или нет какое-либо из этих сообщений.

Вопросы:

  1. Моя схема заботится обо всем, что ей нужно?
  2. Как будет выглядеть пример SQL-запроса, чтобы заполнить чью-то папку «Входящие», добавляя сообщения GLOBAL, а также сообщения PERSONAL - я хотел бы иметь возможность определить, какой именно для пользовательского интерфейса.

И, пожалуйста, не стесняйтесь добавлять в мою схему, если вы считаете, что это будет полезно.

Ответы [ 2 ]

10 голосов
/ 09 июня 2011

Схема выглядит так, как будто она будет работать.Вероятно, должна быть дата создания.Нет способа узнать, прочитали ли вы глобальное сообщение, но не создавая записи для всех.

Вот несколько SQL:

SELECT M.*, MTU.* 
FROM messages M 
    LEFT JOIN message_to_user MTU ON MTU.message_id=M.message_id
WHERE MTU.receiver_id={$UserID} OR M.message_type={$GlobalType}
ORDER BY M.created_on DESC

[РЕДАКТИРОВАТЬ] Проблема: у каждого пользователя должны быть своисобственный уникальный статус «чтение» для глобальных электронных писем.Возможно, вы также захотите дать им возможность «удалить» / скрыть это электронное письмо, чтобы им не приходилось постоянно его просматривать.Невозможно обойтись без создания какой-либо строки для каждого электронного письма по мере его поступления, что, вероятно, обременительно для одновременного выполнения такого количества вкладок ... или, что еще лучше, не создавайте статус, пока он не прочитан.Таким образом, INSERTS для глобальных электронных писем будет происходить только тогда, когда сообщение будет прочитано.

messages
    message_id
    message_type
    sender_id
    timestamp

message_recipient
    message_id
    user_id

message_status
    message_status_id
    message_id
    user_id
    is_read
    read_datetime
    is_deleted
    deleted_datetime

SELECT M.*, MR.*, MS.*
FROM messages M
    LEFT JOIN message_recipient MR ON MR.message_id=M.message_id
    LEFT JOIN message_status MS ON MS.message_id=M.message_id
WHERE 
    (MS.message_status_id IS NULL OR MS.is_deleted = 0)
    (MR.user_id={$UserId} OR M.message_type={$GlobalType})
ORDER BY M.timestamp DESC

[EDIT] Использовать ли message_type в качестве таблицы БД или просто как настройки в вашем коде, отчасти личное предпочтениеи частично ваши потребности.Если вам нужно сделать запрос к БД и увидеть текст «персональный» и «глобальный» непосредственно из вашего запроса, то вы хотите использовать таблицу message_type.Однако, если вам нужен только «тип» для обработки вашей бизнес-логики, но вам не нужно видеть его в результатах запроса, я бы выбрал подход в стиле «Enum».Перечисления - это вещь C # ... в PHP ближе всего у вас есть класс с константами ... что-то вроде:

class MessageTypes {
    public const Global   = 0;
    public const Personal = 1;
}

Итак, ваш запрос будет: WHERE ... message_type=".MessageTypes::Global."...

5 голосов
/ 09 июня 2011

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

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

messages_tbl
 - message_id    |  int(11)  | Primary Key / Auto_Increment
 - message_type  |  int(11)
 - sender_id     |  int(11)  | FK to sender
 - receiver_id   |  int(11)  | FK to receiver
 - status        |  int(1)   | 0/1 for Unread / Read
 - message       |  text
 - date          |  datetime

global_message_tbl
 - g_message_id   |  int(11)  | Primary Key / Auto_Increment
 - g_message_type |  int(11)
 - sender_id      |  int(11)  | FK to sender
 - date           |  datetime

global_readstatus_tbl
 - user_id       |  int(11)   | Primary Key
 - g_message_id  |  int(11)   | Primary Key
 - date          |  datetime

В качестве альтернативы объедините messages_tbl и global_message_tbl, чтобы каждый пользователь лично отправлял глобальное сообщение в цикле.Это сокращает вашу схему до одной таблицы.

messages_tbl
 - message_id    |  int(11)     | Primary Key / Auto_Increment
 - sender_id     |  int(11)     | FK to sender
 - receiver_id   |  int(11)     | FK to receiver
 - status        |  int(1)      | 0/1 for Unread / Read
 - message_type  |  varchar(8)  | Personal / Global / Company
 - message       |  text
 - date          |  datetime
 - type          |  varchar(8)  

Если вы хотите немного лучше нормализовать вашу таблицу и упростить добавление типов сообщений в будущем, переместите message_type обратно в свой собственныйснова создайте таблицу и сделайте message_type FK для message_type_id

message_type_tbl
 - message_type_id  |  int(11)    | Primary Key / Auto_Increment
 - message_type     |  varchar(8) | Personal / Global / Company

Обновление - таблица образцов (1 таблица)

message_tbl

message_id | message_type | sender_id | receiver_id |  status  |  message  |      datetime
    1      |   personal   |     2     |      3      |   read   |  foobar   |  12/04/11 00:09:00
    2      |   personal   |     2     |      4      |  unread  |  foobar   |  12/04/11 00:09:00
    3      |   personal   |     3     |      2      |  unread  |  barfoo   |  12/04/11 02:05:00
    4      |   global     |     1     |      2      |  unread  |  gmessage |  13/04/11 17:05:00
    5      |   global     |     1     |      3      |  unread  |  gmessage |  13/04/11 17:05:00
    6      |   global     |     1     |      4      |   read   |  gmessage |  13/04/11 17:05:00

user_tbl

 user_id  |  name
    1     |  Admin
    2     |  johnsmith
    3     |  mjordan
    4     |  spippen

Выше предполагается, что пользователи 2, 3 и 4 являются обычными пользователями, отправляющими сообщения друг другу, пользователь 1 - это учетная запись администратора, которая будет использоваться для отправки глобальных сообщений.(доставляется непосредственно каждому пользователю индивидуально), позволяя вам видеть ту же информацию, как если бы это было личное сообщение.

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

Если вы не ожидаете, что ваши пользователи будут отправлять миллионы сообщений в день, а также регулярноГлобальныйсообщения миллионам пользователей, тогда количество строк не должно быть проблемой.Вы всегда можете удалить старые прочитанные сообщения от пользователей, создав сценарий очистки.

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