Facebook喜欢通知跟踪(数据库设计)

Ati*_*din 39 mysql database-design data-modeling

我只想弄清楚Facebook的数据库是如何构建用于跟踪通知的.

我不会像Facebook那样复杂化.如果我们想象一个简单的通知表结构:

notifications (id, userid, update, time);

我们可以使用以下方式获取朋友的通知:

SELECT `userid`, `update`, `time`
FROM `notifications`
WHERE `userid` IN 
(... query for getting friends...)
Run Code Online (Sandbox Code Playgroud)

但是,应该是什么表结构来检查哪些通知已被读取,哪些没有?

Ati*_*din 40

我不知道这是否是最好的方法,但由于我没有得到任何人的想法,这就是我要做的.我希望这个答案也可以帮助其他人.

我们有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
Run Code Online (Sandbox Code Playgroud)

我们的想法是从通知表中选择通知并加入notificationsRead表并检查上次读取的通知和ID> notificationid的行.每次打开通知页面时,都会更新notificationsRead表中的行.

查询未读通知我猜想会是这样的..

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...
))
Run Code Online (Sandbox Code Playgroud)

不检查上面的查询.感谢@espais的db设计理念

  • 如果您不想要第二个表,则可以将最后一个读取属性保存在用户表中 (13认同)
  • 为什么需要这种连接?只需将阅读字段放在通知表中,您就可以节省时间和空间。 (2认同)
  • `notificationsread`表将为每个用户仅存储1行.当用户将其通知查看到最新的notificationID时,将更新该更新.所以我们实际上并不需要那个领域.谢谢你的评论:) (2认同)
  • 我认为“ Jasie”的意思是,为什么您甚至需要“ notificationRead”表。只是在您的`notification`表中添加一个`readStatus`字段是否有问题。因此,在创建通知时,其“ readStatus”为false,并且只有在用户打开通知页面时才变为“ true”。 (2认同)
  • 我认为当您向多个人发送相同的通知(例如群组通知等)时,这种设计比单表设计更好。此类通知将仅使用主表中的一行,随后可以在通知人们时使用该通知的外键添加新行。说啥? (2认同)

the*_*e_e 9

你可以添加另一个表...

tblUserNotificationStatus
-------------------------
- id (pk)
- notification_id
- user_id
- read_status (boolean)
Run Code Online (Sandbox Code Playgroud)

如果您想保留历史记录,可以保留X最新通知,并删除比列表中最后一个通知旧的剩余通知....


Joe*_*bel 7

如果在您发出通知时,您提供了当时可用的所有相关通知,则可以通过将时间戳附加到可通知事件并跟踪每个用户上次收到通知的时间来简化此操作.但是,如果您处于多服务器环境中,则必须注意同步.请注意,此方法不需要真正的日期时间戳,只需要单调增加.


Kar*_*ner 6

我发现这里没有人解决这样一个事实:通知通常会重复出现。即将进行的交易的通知始终是相同的,但其中包含不同的交易 ID 或日期。像这样:{您有一笔新的即将付款:@ paymentID,到期日为@ dueDate }。将文本放在不同的表中也可以帮助

  1. 如果您想稍后更改通知文本
  2. 使应用程序多语言化更容易,因为我只需使用语言代码对通知表进行分层并检索适当的字符串

因此,我还为这些抽象通知制作了一个表格,这些抽象通知只是在用户下链接到一个中间表,其中一种通知类型可以多次发送给一个用户。我还不是通过外键 ID 将通知链接到用户,但我为所有通知创建了通知代码,并为这些代码的 varchar 字段建立了 full_text 索引,以提高读取速度。由于这些通知需要在特定时间发送,因此开发者编写起来也更容易

NotificationService::sendNew( Notification::NOTE_NEW_PAYMENT, ['paymentId'] => 123, ['dueDate'] => Carbon::now(), 'userIdToSendTo' );
Run Code Online (Sandbox Code Playgroud)

现在,由于我的消息中将包含自定义数据,这些数据将插入到字符串中,正如您事先从第二个参数中看到的那样,然后我会将它们存储在数据库 blob 中。像这样

$values = base64_encode(serialize($valuesInTextArray));
Run Code Online (Sandbox Code Playgroud)

这是因为我想将通知与其他表解耦,因此我不想在通知表之间建立不必要的 FK 关系,这样我就可以说通知 234 附加到事务 23,然后加入并获取该关系交易ID。将其解耦可以消除管理这些关系的开销。缺点是,几乎不可能删除通知,例如删除交易时,但在我的用例中,我决定,无论如何都不需要这样做。

我将在App端检索并填充文本,如下所示。诗。我正在使用某人的 vksprintf 函数(https://github.com/washingtonpost/datawrapper/blob/master/lib/utils/vksprintf.php),支持他!

$valuesToFillInString = unserialize(base64_decode($notification->values));
vksprintf( $notificationText->text, $valuesToFillInString )
Run Code Online (Sandbox Code Playgroud)

另请注意我索引了哪些字段,因为我将按它们查找或排序

我的数据库设计如下

================================

表:用户

  • 编号(PK)

================================

表:通知

  • 编号(PK)
  • user_id(fk,已索引)
  • text_id(fk - 通知文本表)
  • 值(blob)[包含要输入到文本字符串中的值数组]
  • 创建日期时间(日期时间)
  • 读取(布尔值)

[ClusterIndex] => (user_id, 创建日期时间)

================================

表:通知文本

  • 编号(PK)
  • text_id(唯一索引)
  • text (varchar) [{ 您有一笔新的即将付款:@ paymentID,到期日为 @dueDate }]
  • note (varchar, nullable) [开发人员注释,信息栏]