猫鼬私聊消息模型

时间:2014-11-14 18:35:43

标签: node.js mongodb mongoose

我尝试在用户之间添加私人消息传递到我的数据模型中。我在两种可能的方式之间来回走动。

1)每个用户都有一个user_id,chat_id对的数组,对应于他们参与的聊天。聊天模型只存储chat_id和消息数组。

2)不要与用户存储聊天,只需让Chat模型存储一对user_id和一组消息。

选项(1)的问题是每当用户加入或开始聊天时,我都需要首先查看数组,以便用户查看user_id,chat_id对是否已经存在。然后在Chat中为chat_id做第二次查找。如果它不存在,我需要为两个参与的用户在两个不同的地方创建user_id,chat_id对。

使用选项(2),我将在聊天模型中搜索user_id1,user_id2对,如果我找到它,我就完成了,如果没有,我会为该对创建一个新的聊天记录并完成。 / p>

基于此选项(2)看起来似乎是处理此问题的更好方法。但是,我遇到了解决如何建模"对的问题。用户ID的方式可以在聊天模型中轻松搜索。即使user_ids以错误的顺序传递,即如何user_id2,user_id1,我如何确保我能找到聊天记录。在Mongoose中建模的最佳方法是什么?

var chatSchema = mongoose.Schema({

  messages: [{
        text: { 
          type: String,
          max: 2000
        },
        sender: { 
          type: mongoose.Schema.Types.ObjectId, 
          ref: 'User'
        }
      }],
  participant1: [{                
          type: mongoose.Schema.Types.ObjectId, 
          ref: 'User'
        }]
  participant2: [{                
          type: mongoose.Schema.Types.ObjectId, 
          ref: 'User'
        }]
});

如果它是如上所述,我将如何搜索参与者对?我可以以某种方式订购参与者ID,以便他们始终是参与者1<例如,参与者2,使搜索更简单?

2 个答案:

答案 0 :(得分:5)

一些建议。

首先 - 为什么将Participant1和2存储为数组?有一个特定的发件人和一个(或多个)收件人(取决于您是否需要组邮件)。

考虑以下架构:

var ChatSchema = new Schema({
    sender : {
        type : mongoose.Schema.Types.ObjectId,
        ref : 'User'
    },
    messages : [
        {
            message : String,
            meta : [
                {
                    user : {
                        type : mongoose.Schema.Types.ObjectId,
                        ref : 'User'
                    },
                    delivered : Boolean,
                    read : Boolean
                }
            ]
        }
    ],
    is_group_message : { type : Boolean, default : false },
    participants : [
        {
            user :  {
                type : mongoose.Schema.Types.ObjectId,
                ref : 'User'
            },
            delivered : Boolean,
            read : Boolean,
            last_seen : Date
        }
    ]
});

此架构允许一个聊天文档存储所有消息,所有参与者以及与每条消息和每个参与者相关的所有状态。

布尔值is_group_message只是一种过滤直接/组消息的简短方法,可能用于客户端查看或服务器端处理。直接消息显然更易于查询,但两者都非常简单。

meta数组列出了单个邮件的每个参与者的已发送/已读状态等。如果我们不处理群组消息,这不一定是一个阵列,但我们是,所以没关系。

主文档(而不是元子文档)上的deliveredread属性也只是告知最后一条消息是否已发送/读取的简写方式。他们在每次写入文档时都会更新。

此架构允许我们将聊天的所有内容存储在一个文档中。甚至是群聊。

答案 1 :(得分:3)

嗯,这个问题没有正确的答案,但是,你提到的方法肯定不是最好的!

首先,当您考虑设计“聊天”模型时,您需要考虑用户之间会有数百万条消息,因此当您想要获取时需要关注性能聊天。

将消息存储到数组中根本不是一个好主意,您的模型的大小将会很大,您必须考虑到MongoDB的文档大小限制目前是每个文档16 MB。

https://docs.mongodb.com/manual/reference/limits/

其次,您必须考虑分页方面,因为它会影响聊天时的性能,当您检索2个用户之间的聊天时,您不会在开始时请求所有聊天,只会请求最新的,然后如果用户滚动聊天,您可以请求较旧的,这方面非常重要,并且由于其对性能的影响而不能忽略。

我的方法是将每封邮件存储在一份有针对性的文件中

首先,将每条消息存储在一个文档中将提高您在获取聊天记录期间的性能,并且文档大小将非常小。

这是一个非常简单的例子,你需要根据你的需要改变模型,它只是代表这个想法:

const MessageSchema = mongoose.Schema({
    message:{
        text: { type:String, required:true }
        // you can add any other properties to the message here.
        // for example, the message can be an image ! so you need to tweak this a little
    }
    // if you want to make a group chat, you can have more than 2 users in this array
    users:[{
        user: { type:mongoose.Schema.Types.ObjectId, ref:'User', required:true }
    }]
    sender: { type:mongoose.Schema.Types.ObjectId, ref:'User', required:true },
    read: { type:Date }
},
{
    timestamps: true
});

您可以通过此查询获取聊天内容:

 Message.find(({ users: { "$in" : [#user1#,#user2#]} })
    .sort({ updatedAt: -1 })
    .limit(20)

简单又干净! 如你所见,采用这种方法,分页变得非常容易。