web-dev-qa-db-ja.com

電子メールメッセージングシステムのデータベース設計

Gmailのようなメールメッセージングシステムを作りたいです。次のオプションが欲しいです:スター付き、ゴミ箱、スパム、ドラフト、既読、未読。現在、データベースには以下の構造があります。

CREATE TABLE [MyInbox](
    [InboxID] [int] IDENTITY(1,1) NOT NULL,
    [FromUserID] [int] NOT NULL,
    [ToUserID] [int] NOT NULL,
    [Created] [datetime] NOT NULL,
    [Subject] [nvarchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
    [Body] [nvarchar](max) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
    [IsRead] [bit] NOT NULL,
    [IsReceived] [bit] NOT NULL,
    [IsSent] [bit] NOT NULL,
    [IsStar] [bit] NOT NULL CONSTRAINT [DF_MyInbox_IsStarred]  DEFAULT ((0)),
    [IsTrash] [bit] NOT NULL CONSTRAINT [DF_MyInbox_IsTrashed]  DEFAULT ((0)),
    [IsDraft] [bit] NOT NULL CONSTRAINT [DF_MyInbox_Isdrafted]  DEFAULT ((0))
) ON [PRIMARY]

しかし、私は上記の構造でいくつかの問題に直面しています。現在、ユーザーAがメッセージをユーザーBに送信すると、このテーブルに行が格納されますが、ユーザーBがそのメッセージを削除すると、ユーザーAが送信したメッセージも削除されます。これは間違っています。通常の電子メールメッセージングシステムとまったく同じようにしたいと思います。 Aが送信済みアイテムからメッセージを削除した場合、Bは受信ボックスから削除されるべきではありません。私はここで、ユーザーAが一度に500人のユーザーにメールを送信したと仮定して、他の問題について考えています。私の設計では、500行に重複した本文があります。つまり、メモリ効率の高い保存方法ではありません。メッセージングシステムのデザインを作るのを手伝ってくれませんか?

23
AsifQadri

そのためにテーブルを分割する必要があります。あなたは以下のスキーマと構造を持つことができます

CREATE TABLE [Users]
    (
      [UserID] INT ,
      [UserName] NVARCHAR(50) ,
      [FirstName] NVARCHAR(50) ,
      [LastName] NVARCHAR(50)
    )

CREATE TABLE [Messages]
    (
      [MessageID] INT ,
      [Subject] NVARCHAR(MAX) ,
      [Body] NVARCHAR(MAX) ,
      [Date] DATETIME,
      [AuthorID] INT,
    )

CREATE TABLE [MessagePlaceHolders]
    (
      [PlaceHolderID] INT ,
      [PlaceHolder] NVARCHAR(255)--For example: InBox, SentItems, Draft, Trash, Spam 
    )

CREATE TABLE [Users_Messages_Mapped]
    (
      [MessageID] INT ,
      [UserID] INT ,
      [PlaceHolderID] INT,
      [IsRead] BIT ,
      [IsStarred] BIT 

    )

ユーザーテーブルでは、ユーザーを指定できます。「メッセージ」は、メッセージのテーブルを示します。 「MessagePlaceHolders」は、メッセージのプレースホルダーのテーブルを示します。プレースホルダーには、受信トレイ、送信済みアイテム、下書き、スパム、ゴミ箱などがあります。 「Users_Messages_Mapped」は、ユーザーとメッセージのマッピングテーブルを示します。 「UserID」と「PlaceHolderID」は外部キーです。「IsRead」と「IsStarred」は、それらの名前が何を表すかを示します。 「Users_Messages_Mapped」テーブルに特定のメッセージIDのレコードが見つからない場合、そのレコードは不要になったため、メッセージテーブルから削除されます。

34
Raghav

スキーマをさらに分解する必要があると思います。電子メールを個別に保存し、受信トレイをそれらに含まれるメッセージにマップします。

4
PaulJWilliams

ドキュメント指向の作業をしている場合は、 CouchDB を確認することをお勧めします。これはスキーマレスであり、このような問題は解消されます。

例を見てみましょう。AがBにメッセージを送信し、Bによって削除されます。

電子メールの属性としてrecipientsがリストされた、ドキュメントの単一のインスタンスがあります。ユーザーがメッセージを削除すると、受信者リストからメッセージを削除するか、deleted_byまたは選択したもののリストに追加します。

これは、これまでのデータとは大きく異なるアプローチですが、時間をかけて検討することは非常に有益な場合があります。

4
Tim McNamara

私があなただったら、両方のフラグがtrueの場合、送信者用と受信者用の2つのフラグを設定します。両方のフラグがtrueの場合、メッセージはデータベースから削除されます。

ゴミについても同じことをします。 cronを実行するか、送信者と受信者の両方がメッセージを削除してからデータベースから削除するかどうかを手動で確認することをお勧めします。

2
Maximus

メールボックスにメッセージを持っている人に各メッセージを結合するMessageContactsのテーブルを作成できます。ユーザーがメッセージを削除すると、MessageContactsから行が削除されますが、元のメッセージは保持されます。

あなたはそれをすることができます...しかし、私はあなたがそうしないことを提案します。それがあなたの家庭教師によって設定された学術的な演習でない限り、あなた自身のメッセージングシステムを開発することは確かに時間の完全な無駄です。もしそれが宿題なら、あなたはそう言うべきです。そうでない場合は、代わりにもっと便利なことを行ってください。

1
nvogel
CREATE TABLE `mails` (  
  `message_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,  
  `message` varchar(10000) NOT NULL DEFAULT '',  
  `file` longblob,  
  `mailingdate` varchar(40) DEFAULT NULL,  
  `starred_status` int(10) unsigned NOT NULL DEFAULT '0',  
  `sender_email` varchar(200) NOT NULL DEFAULT '',  
  `reciever_email` varchar(200) NOT NULL DEFAULT '',  
  `inbox_status` int(10) unsigned NOT NULL DEFAULT '0',   
  `sent_status` int(10) unsigned NOT NULL DEFAULT '0',  
  `draft_status` int(10) unsigned NOT NULL DEFAULT '0',  
  `trash_status` int(10) unsigned NOT NULL DEFAULT '0',  
  `subject` varchar(200) DEFAULT NULL,  
  `read_status` int(10) unsigned NOT NULL DEFAULT '0',  
  `delete_status` int(10) unsigned NOT NULL DEFAULT '0',  
  PRIMARY KEY (`message_id`)  
)

このテーブルを使用してメールを保存し、メールボックスに従ってクエリを操作できます。ユーザーの詳細やログインの詳細テーブルなど、残りのテーブルは避けています。必要に応じて作ることができます。

1
Gaurav Singhal

削除する理由何も削除する必要はないと思います。削除されたときにユーザーから非表示にするだけです。なぜなら、送信者が多くの受信者に同じメッセージを送信するとき、両側をチェックすることは問題になるからです。次に、すべての受信者を確認してフラグを立てる必要があります。よろしければ削除…何も削除する必要はないと思います。

0
Elvin Nagiyev

私の構造では、「deleted:bool」フラグを設定し、その値に応じてメッセージを表示するか非表示にします。

0
P. Lusine

メッセージは一度に1つのフォルダーにしか入れることができないため、フォルダーテーブル(「ゴミ箱」、「受信トレイ」、「アーカイブ」などを含む)とメッセージからフォルダーへの外部キーが必要です。ラベルの場合、多対多の関係があるため、ラベルテーブルとリンクテーブル(messages_labels)も必要です。スターを付けるには、「未読」の場合と同じように、単純なビット列で十分です。

0
tdammers