Facebook, как отслеживание уведомлений (DB Design)
Я просто пытаюсь понять, как структура базы данных Facebook структурирована для отслеживания уведомлений.
Я не буду вдаваться в сложность, как Facebook. Если мы представим простую структуру таблиц для notificaitons:
notifications (id, userid, update, time);
Мы можем получать уведомления друзей, используя:
SELECT `userid`, `update`, `time`
FROM `notifications`
WHERE `userid` IN
(... query for getting friends...)
Однако какова должна быть структура таблицы, чтобы проверить, какие уведомления были прочитаны, а какие нет?
Ответы
Ответ 1
Я не знаю, лучший ли это для этого, но поскольку у меня нет идей от кого-либо еще, это то, что я буду делать. Я надеюсь, что этот ответ может помочь и другим.
У нас есть 2 таблицы
notification
-----------------
id (pk)
userid
notification_type (for complexity like notifications for pictures, videos, apps etc.)
notification
time
notificationsRead
--------------------
id (pk) (i dont think this field is required, anyways)
lasttime_read
userid
Идея состоит в том, чтобы выбирать уведомления из таблицы уведомлений и присоединяться к таблице уведомлений и проверять последнее уведомление и строки чтения с идентификатором > уведомлять. И каждый раз, когда открывается страница уведомлений, обновляйте строку из таблицы уведомлений.
Запрос на непрочитанные уведомления, я думаю, будет таким.
SELECT `userid`, `notification`, `time` from `notifications` `notificationsRead`
WHERE
`notifications`.`userid` IN ( ... query to get a list of friends ...)
AND
(`notifications`.`time` > (
SELECT `notificationsRead`.`lasttime_read` FROM `notificationsRead`
WHERE `notificationsRead`.`userid` = ...$userid...
))
Вышеуказанный запрос не установлен.
Благодаря идее дизайна db от @espais
Ответ 2
Вы можете добавить другую таблицу...
tblUserNotificationStatus
-------------------------
- id (pk)
- notification_id
- user_id
- read_status (boolean)
Если вы хотите сохранить историю, вы можете сохранить X последних уведомлений и удалить остальные, которые старше вашего последнего уведомления в списке....
Ответ 3
Если при предоставлении уведомлений вы даете все соответствующие уведомления, доступные в то время, вы можете сделать это проще, добавив отметки времени к уведомляемым событиям и отслеживая, когда каждый пользователь последний раз получал уведомления. Однако, если вы работаете в многосерверной среде, вам нужно быть осторожным в синхронизации. Обратите внимание, что для этого подхода не требуются истинные штампы даты, а только одно, что монотонно возрастает.
Ответ 4
Я вижу, что здесь никто не обращается к факту, что уведомления обычно повторяются, ака. уведомление о предстоящей транзакции всегда будет одинаковым, но с другим идентификатором транзакции или датой в нем. так: {У вас есть новый предстоящий платеж: @paymentID, с установленной датой @dueDate}.
Наличие текстов в другой таблице также может помочь с
- Если вы хотите изменить текст уведомления позже,
- Сделать многоязычное приложение проще, потому что я могу просто наложить таблицу уведомлений на код языка и получить нужную строку
Таким образом, я также сделал таблицу для тех абстрактных уведомлений, которые просто связаны с пользователем с средней таблицей, где один тип уведомления может быть отправлен одному пользователю несколько раз. Я также связал уведомления с пользователем не с помощью идентификатора внешнего ключа, но я сделал коды уведомлений для всех уведомлений, а full_text проиндексировал поле varchar этих кодов для более быстрой скорости чтения. В связи с тем, что эти уведомления необходимо отправлять в определенное время, разработчику также проще писать
NotificationService::sendNew( Notification::NOTE_NEW_PAYMENT, ['paymentId'] => 123, ['dueDate'] => Carbon::now(), 'userIdToSendTo' );
Теперь, когда мои сообщения собираются иметь в них пользовательские данные, которые вставляются в строку, как вы можете видеть из второго аргумента заранее, я буду хранить их в блоке базы данных. как таковой
$values = base64_encode(serialize($valuesInTextArray));
Это связано с тем, что я хочу отделить уведомления от других таблиц, и поэтому я не хочу ссылаться на необязательные отношения FK из таблицы уведомлений и из нее, так что я могу, например, сказать, что уведомление 234 прикреплено к транзакции 23, а затем присоединяется и получить этот идентификатор транзакции. Развязывание это устраняет накладные расходы на управление этими отношениями. Недостатком является то, что удаление уведомлений почти невозможно, когда, например, удаляется транзакция, но в моем случае я решил, что это все равно не нужно.
Я буду извлекать и заполнять тексты на стороне приложения следующим образом. Ps. Я использую функцию someks vksprintf (https://github.com/washingtonpost/datawrapper/blob/master/lib/utils/vksprintf.php), реквизит для него!
$valuesToFillInString = unserialize(base64_decode($notification->values));
vksprintf( $notificationText->text, $valuesToFillInString )
Обратите внимание, какие поля я индексирую, потому что я собираюсь их найти или отсортировать
Моя конструкция базы данных выглядит следующим образом
==============================
ТАБЛИЦА: Пользователи
==============================
ТАБЛИЦА: Уведомления
- id (pk)
- user_id (fk, индексированный)
- text_id (fk - таблица NotificationTexts)
- значения (blob) [содержащие массив значений для ввода в текстовую строку]
- createdDateTime (DateTime)
- read (boolean)
[ClusterIndex] = > (user_id, createdDateTime)
==============================
ТАБЛИЦА: NotificationTexts
- id (pk)
- text_id (индексированный uniquem)
- text (varchar) [{У вас есть новый предстоящий платеж: @paymentID с датой окончания @dueDate}]
- note (varchar, nullable) [примечания для разработчиков, информационный столбец]
Ответ 5
Ниже приведены таблицы
Пользователь
- userId (целое число)
- FULLNAME (VarChar)
Уведомление
- notificationId (Integer)
- createDate (Дата)
- notificationDetailUrl (VarChar)
- isRead (bollean)
- описание (VarChar)
- userId (F.K)