猫鼬私人聊天消息模型

Pra*_*era 4 mongoose mongodb node.js

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

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

2)根本不存储与用户的聊天,而让Chat模型存储一对user_id和消息数组。

选项(1)的问题是,无论何时用户加入或开始聊天,我都需要先通过数组查找该用户,以查看user_id和chat_id对是否已经存在。然后在“聊天”中再次查找chat_id。如果不存在,则需要在两个不同的位置为两个参与的用户创建user_id和chat_id对。

使用选项(2)时,我将在聊天模型中搜索user_id1,user_id2对,如果找到了,就完成了;否则,我将为该对创建新的Chat记录并完成。

基于此选项(2)似乎是处理此问题的更好方法。但是,我遇到了一些问题,他们想出如何在聊天模型中轻松搜索用户ID的“对”模型。即,即使以错误的顺序传递了user_id,也如何确保可以找到聊天记录,即user_id2,user_id1。在猫鼬中对此建模的最佳方法是什么?

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'
        }]
});
Run Code Online (Sandbox Code Playgroud)

如果是上述情况,我将如何搜索参与者对?我能否以某种方式对参与者ID进行排序,以使它们始终是participant1 <participant2,例如,使搜索更简单?

May*_*ndi 11

好吧,这个问题没有正确的答案,但是可以肯定的是,您提到的方法根本不是最好的!

首先,当你在考虑设计一个“聊天”模型时,你需要考虑到用户之间会有数百万条消息,所以当你想要获取聊天时,你需要关心性能。

将消息存储到数组中根本不是一个好主意,到时候您的模型的大小会很大,您必须考虑到 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
});
Run Code Online (Sandbox Code Playgroud)

您可以通过此查询获取聊天记录:

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

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

  • 您应该为对话创建一个新集合。在您的模式中,存在数据重复。假设这是一个由 100 名成员组成的组。因此每个文档都包含 100 个 ObjectId(User) 成员的数组。这些愚蠢的数据会更快地填满您的磁盘空间! (2认同)

Aug*_*ner 8

一些建议。

首先-为什么将参与者1和参与者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
        }
    ]
});
Run Code Online (Sandbox Code Playgroud)

这种模式允许一个聊天文档存储所有消息,所有参与者以及与每个消息和每个参与者相关的所有状态。

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

meta数组列表的递送/读取状态,等等,对于单个消息的每个参与者。如果我们不处理组消息,则不必是数组,但是可以,所以就可以了。

主文档(不是meta子文档)上的deliveredand read属性也是判断最后一条消息是否已传递/未读的简便方法。它们在每次写入文档时都会更新。

这种模式使我们可以将有关聊天的所有信息存储在一个文档中。甚至是群聊。