【问题标题】:How to keep track of a private messaging system using MongoDB?如何使用 MongoDB 跟踪私人消息系统?
【发布时间】:2010-04-20 01:04:49
【问题描述】:

使用 facebook 的私人消息系统,您必须在其中跟踪消息内容的发送者和接收者。如果我使用 MySQL,我会有多个表,但使用 MongoDB,我会尽量避免所有这些。我正在尝试提出一个可以扩展且易于维护的“好”模式。如果我使用 mysql,我将有一个单独的表来引用用户和消息。见下文...

个人资料表

user_id
first_name
last_name

消息表

message_id
message_body
time_stamp

user_message_ref 表

user_id (FK)
message_id (FK)
is_sender (boolean)

使用上面列出的架构,我可以查询“Bob”可能拥有的任何消息,无论他是收件人还是发件人。

现在如何将其转换为适用于 MongoDB 的模式。我想我会有一个单独的集合来保存消息。问题是,我如何区分发件人和收件人?如果 Bob 登录,我要查询什么?根据 Bob 是否发起了电子邮件,我不想为了查看邮件是否属于用户而查询“发件人”和“收件人”。

我访问了 MongoDB 的消息组,发现一些可行的方法。 每条消息都将被视为“博客”帖子。创建消息后,将两个用户(无论最初的发送者/接收者是谁)添加到一个数组中。之后的每个响应都将被视为注释,将插入到数组中。

留言

{
    "_id" : <objectID>,
    "users" : ["bob", "amy"],
    "user_msgs" :
        [
            { 
                "is_sender" : "bob",
                "msg_body" : "Hi Amy, how are you?!",
                "timestamp" : <generated by Mongo>
            }
            { 
                "is_sender" : "amy",
                "msg_body" : "Bob, long time no see, how is the family?!",
                "timestamp" : <generated by Mongo>
            }
        ]
}

这样我可以查询涉及“Bob”的消息,并遍历“user_msgs”数组。我将能够分辨出发件人是谁并按时间戳排序。

【问题讨论】:

  • 看起来不错的设计。但我遇到了一个问题。我想实现对话线程。因此,当用户打开他的消息时,他应该看到每个对话线程的最后一条消息(发送或接收无关紧要)。所以 Bob 将看到最后一次与 Amy、Chris 和 Ann 交换的消息……(例如,它在 LinkedIn 上就是这样工作的)。但我不知道如何查询这个。因此,对于当前的模式:对于涉及 Bob 的每一篇“博客文章”,我只需要从嵌入式数组中获取最后一条消息。有什么想法吗?

标签: mongodb


【解决方案1】:

想通了。请参阅我在原始帖子中的上述解释。

【讨论】:

  • 您是否错过了某种通知的“is_read”属性?如果不是,是什么架构?
【解决方案2】:
Your Db Schema Should be like this->

let chatImages = {
    original  : {type:String,required:true,trim:true},
    thumbnail : {type:String,required:true,trim:true}
};

let Chats = new Schema({
    CommonId  : {type: String, trim: true, index: true, unique: true,sparse: true},
    senderId   : {type: Schema.Types.ObjectId,index: true,required:true,ref:'User'},
    receiverId : {type: Schema.Types.ObjectId,index: true,required:true,ref:'User'},
    messageId  : {type: String, trim: true, index: true, unique: true,sparse: true},
    isDeliver  : {type: Boolean, default: false},
    isSent     : {type: Boolean, default: true},
    chatType   : {
                 type: String,required:true,enum: [
                 Config.APP_CONSTANTS.DATABASE.CHAT_TYPE.TEXT,
                 Config.APP_CONSTANTS.DATABASE.CHAT_TYPE.IMAGE
                 ],default:Config.APP_CONSTANTS.DATABASE.CHAT_TYPE.TEXT},
    text       : {type: String, trim: true, index: true,sparse: true},
    sentAt     : {type:Number, default: Date.now,index:true,required: true},
    chatImage  : {type:chatImages},
});

CommonId 如果您想要像whatsApp 这样的屏幕,您可以看到与您聊天的人,那么CommonId 非常重要。 1)它使分组非常容易(使用$groupBy)。

你可以通过比较receiverId和SenderId来生成CommonId,它是升序的把它放在CommonId

我认为这是一个很好的解释

【讨论】:

    【解决方案3】:

    您将需要在两个集合(用户和消息)之间建立某种链接。

    就个人而言,我会保持简单,并添加两个额外的字段来跟踪发件人和收件人的 id,如下所示:

    {
        _id: /* whatever_id */,
        message_body: "This is the message",
        date_sent: 2010-04-20T10:35,
        sender_id: /*id_of_sender*/,
        recipient_id: /* id_of_recipient */
    }
    

    sender_idrecipient_id 字段将只保存相应用户的值(很可能是一些 ObjectID 实例,尽管您可以分配任何您喜欢的值)对应于用户中相应条目的 _id 字段收藏。您将能够适当地查询这些以获取您所关注的消息(或计算它们,或其他任何东西)。

    另一种方法可能是有效地做同样的事情,但对发送者和接收者使用正式的DBRef,而不是仅仅输入他们的 ID。这可能同样有效,但我倾向于使用以前的解决方案只是因为它更简单,可能更容易查询。

    这两种解决方案都需要再次往返数据库以获取适当的用户文档(例如,用于显示“from”和“to”名称)。


    编辑:
    看来我误解了您要实现的目标-我不知道 Facebook 消息传递包含任何线程概念。但是,您在上面提出的解决方案看起来不错。就个人而言,我会保留用户的 ID 而不是他们的姓名(alice 和 bob),但除此之外它看起来很可行。

    【讨论】:

    • 这将使“线程”成为一场噩梦。我不可能像 Facebook 那样以对话形式展示它。
    • 嗯,我不熟悉 Facebook 的消息传递。我只是假设每条消息都是它自己的实体,我没有意识到它有线程的概念。如有误解请见谅。
    • 嘿没问题,我一开始就想到了你的想法,如果我再创建一个 twitter 就有意义了。不过感谢您的建议!
    • 你说得对,我会使用 ID 而不是用户名,以防用户名因某种原因发生更改。
    猜你喜欢
    • 2012-10-04
    • 2012-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-16
    • 2016-05-07
    • 2010-10-20
    • 2011-08-02
    相关资源
    最近更新 更多