node.js - 使用 MongoDB 创建数组并推送到数组

标签 node.js mongodb

我正在尝试创建一个消息系统,将每条消息写入 mongo 条目。我希望消息条目能够反射(reflect)发送消息的用户以及实际的消息内容。这是消息架构:

const MessageSchema = new Schema({
    id: {
        type: String,
        required: true
    },
    messages: {
        type: Array,
        required: true
    },
    date: {
        type: Date,
        default: Date.now
    }
});

这是我创建一个新条目或附加到现有条目的地方:

Message.findOne({ id: chatId }).then(message => {
            if(message){
                Message.update.push({ messages: { 'name': user.name, 'message': user.message } })
            } else {
                const newMessage = new Message(
                    { id: chatId },
                    { push: { messages: { 'name': user.name, 'message': user.message } } }
                )
                newMessage
                    .save()
                    .catch(err => console.log(err))
            }
        })

我希望最终结果看起来像这样:

id: '12345'
messages: [
 {name: 'David', message: 'message from David'},
 {name: 'Jason', message: 'message from Jason'},
 etc.
]

这样的事情可能吗?如果可能的话,关于如何让它发挥作用有什么建议吗?

最佳答案

这个问题包含很多主题(至少在我看来)。我真的很想尝试将这个问题分解为其核心组件:

设计

正如 David 指出的(第一条评论),这里存在一个设计问题 - 不断增长的数组作为子文档并不理想(请参阅此 blog post 了解更多详细信息)。

另一方面 - 当我们想象一个单独的消息集合是什么样子时,它会是这样的:

_id: ObjectId('...') // how do I identify the message
channel_id: 'cn247f9' // the message belong to a private chat or a group
user_id: 1234 // which user posted this message
message: 'hello or something' // the message itself

这也不是那么好,因为我们根据时间重复 channel 和用户 ID。这就是为什么 bucket pattern被使用

那么......这里“最好”的方法是什么?

概念

现在最相关的问题是 - “此聊天应该支持哪些功能和负载?”。我的意思是,许多聊天仅支持消息显示,没有任何进一步的复杂性(例如在消息中搜索)。记住这一点,我们有可能在数据库中存储实际上不相关的信息。

这(几乎)就像在我们的数据库中存储二进制数据(例如图像)。我们可以这样做,但没有真正充分的理由。因此,如果我们不打算支持消息中的全文搜索,则根本没有必要将消息存储在数据库中......

但是..如果我们想支持全文搜索怎么办?好吧 - 谁说我们需要把这个任务交给我们的数据库?我们可以轻松下载消息(使用分页)并在客户端本身进行搜索操作(未找到关键字时,下载上一页并搜索它),从而减轻我们数据库的负载!

所以..从大小、功能和负载方面来看,消息似乎并不适合存储在数据库中(您可能会认为这个结论令人震惊)

重新设计

  • 使用混合方法,将消息存储在带有分页的单独集合中(存储桶模式支持此方式,如 here 中所述)
  • 将消息存储在数据库外部(因为您使用的是 Node.js,您可以考虑使用 chunk store ),仅在数据库本身中保留对它们的引用
  • 根据您的应用需求设置页面大小,并设置计算字段(例如:页面中当前消息的数量),以尽可能减轻数据库负载

架构

channels:
  _id: ObjectId
  pageIndex: Int32
  isLastPage: Boolean
  // The number of items here should not exceed page size
  // when it does - a new document will be created with incremental pageIndex value
  // suggestion: update previous page isLastPage field to ease querying of next page
  messages:          
  [
    { userId: ObjectID, link: string, timestamp: Date } 
  ]
  messagesCount: Int32

最终结论

我知道 - 对于这样一个“简单”的问题来说,这似乎完全是多余的,但是 - Dawid Esterhuizen让我相信,从一开始就设计数据库来支持 future 的负载至关重要,而且总是比过度简化数据库设计要好

底线是,如果您打算有效地设计数据库,仍然需要回答“此聊天应该支持哪些功能和负载?”的问题(例如,找到您的设计以最优化的方式满足您的应用需求的最佳区域)

关于node.js - 使用 MongoDB 创建数组并推送到数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57838200/

相关文章:

javascript - Javascript中有重复声明优化吗?

javascript - '引用错误 : jest is not defined' when running unit test

node.js - 询问对话框 (cli) 不理解 intent 中的 AMAZON.NUMBER 槽

javascript - 为什么这个 promise 被拒绝了?

javascript - 使用 ".create"时如何使用 Mongoose 添加到数组中的对象

node.js - Angular运行错误Object Prototype may only be an Object or null : undefined

mongodb - Laravel 5.5 Mongo DB 错误

c# - 如何制作整数 ID 生成器?

javascript - mongoDB - $push _id 到特定用户

mongodb - 防止 mongodb 接受非本地连接