代码之家  ›  专栏  ›  技术社区  ›  sdot257

如何使用MongoDB跟踪私有消息传递系统?

  •  12
  • sdot257  · 技术社区  · 16 年前

    以Facebook的私人信息系统为例,你必须在其中跟踪消息内容的发送者和接收者。如果我使用mysql,我会有多个表,但是使用mongodb,我会尽量避免这些。我正试图想出一个“好”的模式,它可以扩展并且易于维护。如果我使用mysql,我将有一个单独的表来引用用户和消息。见下文…

    配置文件表

    user_id
    first_name
    last_name
    

    消息表

    message_id
    message_body
    time_stamp
    

    用户消息参考表

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

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

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

    我联系了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”数组。我可以分辨出发送者是谁,并按时间戳排序。

    3 回复  |  直到 8 年前
        1
  •  2
  •   sdot257    16 年前

    明白了。我的解释见原帖。

        2
  •  1
  •   Mark Embling    16 年前

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

    就我个人而言,我会保持简单,并添加两个额外的字段来跟踪发件人和收件人的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_id recipient_id 字段只为适当的用户保存值(很可能是一些 ObjectID 实例,尽管您可以指定您喜欢的任何内容),但它对应于用户集合中相应条目的_id字段。您将能够适当地查询这些消息,以获取您正在搜索的消息(或者对它们进行计数,或者其他任何消息)。

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

    这两个解决方案都需要对数据库进行另一次往返访问,以获取适当的用户文档(例如,用于显示“从”和“到”名称)。


    编辑:
    似乎我误解了你想要达到的目标——我不知道Facebook的消息包含了线程的任何概念。但是,您在上面提出的解决方案看起来是合理的。就我个人而言,我会为用户输入ID而不是他们的名字(Alice&Bob),但除此之外,它看起来非常可行。

        3
  •  1
  •   Ishan Garg    8 年前
    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},
    });
    

    如果你想要像WhatsApp那样的屏幕,在那里你可以看到与你聊天的人,那么commonID非常重要。 1)它使分组非常容易(使用$groupby)。

    您可以通过比较receiverid和senderid(升序)来生成commonid,将其放入commonid

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