web-dev-qa-db-ja.com

Facebookのような通知追跡(DB設計)

私はFacebookのデータベースが通知を追跡するためにどのように構成されているかを理解しようとしています。

Facebookのような複雑さについてはあまり触れません。通知の単純なテーブル構造を想像すると、次のようになります。

notifications (id, userid, update, time);

以下を使用して、友達の通知を取得できます。

SELECT `userid`, `update`, `time`
FROM `notifications`
WHERE `userid` IN 
(... query for getting friends...)

ただし、どの通知が読み取られ、どの通知が読み取られていないかを確認するためのテーブル構造は何ですか?

これがこれを行うための最良の方法であるかどうかはわかりませんが、他の誰からもアイデアを得られなかったので、これは私がやろうとしていることです。この答えが他の人にも役立つことを願っています。

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

アイデアは、notificationsテーブルから通知を選択して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...
))

上記のクエリはチェックされません。 @espaisのdbデザインのアイデアに感謝します

別のテーブルを追加できます...

tblUserNotificationStatus
-------------------------
- id (pk)
- notification_id
- user_id
- read_status (boolean)

履歴を保持したい場合は、X個の最新の通知を保持し、リスト内の最後の通知より古い残りを削除できます。

9
the_e

通知を送信するときに、その時点で利用可能なすべての関連通知を送信する場合は、通知可能なイベントにタイムスタンプを添付し、各ユーザーが最後に通知を受信した日時を追跡することで、これをより簡単にすることができます。ただし、マルチサーバー環境の場合は、同期に注意する必要があります。このアプローチでは真の日時スタンプは必要なく、単調に増加するものであることに注意してください。

7
Joe Mabel

通知は通常、繰り返し発生するという事実は、誰もここで扱っていないようです。今後のトランザクションの通知は常に同じになりますが、トランザクションIDまたは日付が異なります。そのため:{新しい支払い:@paymentID、期日は@dueDate}があります。別のテーブルにテキストがあると、

  1. 後で通知テキストを変更したい場合
  2. アプリを多言語にするのは簡単です。通知テーブルを言語コードで階層化し、適切な文字列を取得できるからです。

したがって、これらの抽象通知のテーブルも作成しました。これらは、ユーザーの下で中央のテーブルにリンクされているだけで、1つの通知タイプを1人のユーザーに複数回送信できます。また、外部キーIDではなく通知をユーザーにリンクしましたが、すべての通知に通知コードを作成し、full_textにそれらのコードのvarcharフィールドにインデックスを付けて、読み取り速度を向上させました。これらの通知は特定の時間に送信する必要があるという事実により、開発者にとっても簡単です

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

メッセージのカスタムデータが文字列に挿入されるので、2番目の引数から事前にわかるように、データベースのblobに保存します。など

$values = base64_encode(serialize($valuesInTextArray));

これは、他のテーブルから通知を分離したいため、通知テーブルとの間で不要なFK関係を作成したくないので、たとえば、通知234がトランザクション23にアタッチされ、それを結合して取得できるようにするためです。トランザクションID。これを分離すると、これらの関係を管理するオーバーヘッドが取り除かれます。欠点は、たとえばトランザクションが削除されたときに通知を削除することはほとんど不可能ですが、私のユースケースでは、これはとにかく必要ないということです。

以下のようにアプリ側のテキストを取得して入力します。 Ps。私は誰かのvksprintf関数を使用しています( https://github.com/washingtonpost/datawrapper/blob/master/lib/utils/vksprintf.php )、彼に小道具を!

$valuesToFillInString = unserialize(base64_decode($notification->values));
vksprintf( $notificationText->text, $valuesToFillInString )

インデックスを付けるフィールドも確認します。これは、フィールドを検索またはソートするためです。

私のデータベース設計は次のとおりです

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

表:ユーザー

  • id(pk)

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

表:通知

  • id(pk)
  • user_id(fk、インデックス付き)
  • text_id(fk-NotificationTextsテーブル)
  • 値(blob)[テキスト文字列に入力する値の配列を含む]
  • createdDateTime(DateTime)
  • 読み取り(ブール値)

[ClusterIndex] =>(user_id、createdDateTime)

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

表:NotificationTexts

  • id(pk)
  • text_id(一意のインデックス付き)
  • text(varchar)[{次回の支払い:@paymentID、期日は@dueDate}]
  • 注(varchar、nullable)[開発者向けの注意、情報列]
3

また、通知システムの設計方法を理解しようとしています。通知ステータス(既読、未読、削除、アーカイブ済みなど)については[〜#〜] enum [〜#〜]の良い候補だと思います。 READ、UNREAD以外に、削除、アーカイブ、閲覧、却下など、2種類以上のステータスが存在する可能性があると思います。

これにより、ニーズの変化に応じて拡張することができます。

また、アクションのURLまたはリンクを格納するフィールドがあると(少なくとも私の場合は)意味があると思います。一部の通知では、リンクをたどるようにユーザーに要求または要求する場合があります。

異なるタイプが必要な場合は、通知タイプも使用するのが妥当です。システム通知(確認メール通知など)とユーザーが通知(友達リクエストなど)があると考えています。

これが適切な通知システムを持つために最低限必要だと思う構造です。

users
-------------
id
username
password
email

notifications
-------------
id
user_id (fk)
notification_type (enum)
notification_status (enum)
notification_action (link)
notification_text
date_created (timestamp)
1
Radmation

表は次のとおりです

ユーザー

  • userId(整数)
  • fullName(VarChar)

通知

  • notificationId(整数)
  • creationDate(日付)
  • notificationDetailUrl(VarChar)
  • isRead(bollean)
  • 説明(VarChar)
  • userId(F.K)