具体地说,我正在考虑一个聊天应用程序,其中一个User
有很多Chat
,每个Chat
有很多Message
。我将如何表达Chat --has-Many--> Message
关系?
最初,我以为我会将Message
ID引用的列表存储在Chat
上,例如Chat
文档可能看起来像
{
_id: ObjectId('507f191e810c19729de860d5'),
title: 'Jack V, Kyle R, Sam P',
messages: [ObjectId('507f191e810c19729de860ea'), ...],
createdAt: 1546284204867
}
这样,每次发送消息时,我都需要$push
到数组,如果删除,则需要$pull
。使代码有些复杂和晦涩,但仍然可行。
然后我从MongoDB docs中获悉,这种方法仅在数组为 small 且增长限制为 时才成立。 为避免可变的,不断增长的数组,最好将Message
保留返回其父chatId
的{{1}}引用
Chat
最后,如果我想获取与猫鼬聊天的消息,
{
_id: ObjectId('507f191e810c19729de860ea'),
body: 'Hey Kyle! Mind if I ask ya a favor?',
chatId: ObjectId('507f191e810c19729de860d5'),
createdAt: 1546284204869
}
据我了解
const chatId = '507f191e810c19729de860d5'
// 1. through IDs array
Chat.findById(chatId).populate('messages').execPopulate()
// or
// 2. through ID ref
Message.find({ chatId })
文档,然后只有这样才能读取它们Message
个文档(可能是数百万个),并比较Message
属性每个这与MongoDB中的 reads 相比 writes 昂贵得多的事实保持一致。我说对了吗?如果是这样,为什么大多数资源推荐方法2?我在MDN docs(见黄框), MongoDB开发人员的50个技巧和窍门和MongoDB文档中看到了它。
对于一对多关系,在父模型上维护ID数组还是在每个子模型上都具有ID引用更好?
答案 0 :(得分:3)
更新写入实际上非常昂贵。插入新文档的速度很快,但是更新要花一些时间,因为您要执行读和写入操作。如果O(r)
是“读取”的时间复杂度,而O(w)
是“写入”的时间复杂度,则更新为O(r+w)
。实际上,如果您在要查询的字段上建立索引,则读取实际上也非常有效,因此通常不必担心。遵循的一般建议是将更新保持在最低限度,而读和插入都可以,尽管只要索引良好,这些操作实际上都不是问题。
此外,我不建议您将Message
规范化为Chat
文档。文档的大小上限为16MB,因此,如果聊天变得特别大,则MongoDB将无法处理。即使它从未超过该限制,也无法优化消息检索-每次要加载聊天时,您都需要一次抓取所有消息,但是在大多数实际情况下,您只需要检索例如最后几十条消息,并根据需要加载更多!此外,将您的邮件保留为单独的文档将使您可以执行其他有用的任务,例如搜索和仅显示特定人员发送的邮件,跳过某些时间点,清除早于给定日期的所有文档,创建TTL索引以自动删除旧邮件等。
因此,从潜在的功能,性能,文档大小的限制甚至是易于管理的角度来看,首选的方法是使用单独的Message
文档,并在其父文档中引用其相应的Chat
。