内嵌文档中的mongodb限制

问题描述 投票:0回答:3

我需要创建一个消息系统,一个人可以与许多用户进行对话。 例如,我开始与 user2、user3 和 user4 交谈,因此他们中的任何人都可以看到整个对话,并且如果对话在任何时候都不是私密的,则任何参与者都可以将任何其他人添加到对话中。

这是我的想法如何做到这一点。 我正在使用 Mongo,我的想法是使用对话框作为实例而不是消息。

架构如下:

{
_id : ...., // dialog Id
'private' : 0 // is the conversation private
'participants' : [1, 3, 5, 6], //people who are in the conversation
'msgs' :[
  {
   'mid' : ...// id of a message
   'pid': 1, // person who wrote a message
   'msg' : 'tafasd' //message
  },
  ....
  {
   'mid' : ...// id of a message
   'pid': 1, // person who wrote a message
   'msg' : 'tafasd' //message
  }
]
}

我可以看到这种方法的一些优点 - 在大型数据库中,很容易找到某些特定对话的消息。 - 将人员添加到对话中会很容易。

但是这里有一个问题,我找不到解决方案: 对话变得太长(以 Skype 为例),他们没有向您显示所有对话,而是向您显示一部分,然后向您显示其他消息。 在其他情况下跳过,限制可以解决问题,但这里我该怎么做呢?

如果这是不可能的,您有什么建议?

mongodb document php-mongodb
3个回答
16
投票

MongoDB 文档解释如何选择数组元素的子范围。

db.dialogs.find({"_id": [dialogId]}, {msgs:{$slice: 5}}) // first 5 comments
db.dialogs.find({"_id": [dialogId]}, {msgs:{$slice: -5}}) // last 5 comments
db.dialogs.find({"_id": [dialogId]}, {msgs:{$slice: [20, 10]}}) // skip 20, limit 10
db.dialogs.find({"_id": [dialogId]}, {msgs:{$slice: [-20, 10]}}) // 20 from end, limit 10

您可以使用此技术仅选择与您的 UI 相关的消息。但是,我不确定这是否是一个好的架构设计。您可能需要考虑将“可见”消息与“存档”消息分开。它可能会使查询变得更容易/更快。


3
投票

如果您的对话包含很多消息,请注意:

  1. 您会注意到切片消息数组的性能显着降低,因为 mongodb 会加载所有消息数组,并在仅返回到驱动程序之前对列表进行切片。
  2. 此方法可能会达到文档大小限制(目前为 16MB)。

我的建议是:

  1. 使用两个集合:一个用于对话,另一个用于消息。
  2. 在消息中使用 dbref 进行对话(使用消息时间戳索引该字段,以便能够根据用户请求选择较旧的范围)。
  3. 为每个对话额外使用单独的上限集合。如果你像“conversation_”那样构建它,那么通过名称很容易找到它

结果:

  • 您必须将所有消息写两次。但分成单独的集合,这是正常的。
  • 当您想要显示您的对话时,您只需以“自然排序顺序”从一个集合中选择所有数据,速度非常快。 您的上限收藏将自动存储最后的消息并删除旧的。
  • 您可以通过查询主消息集合来显示用户请求上的旧消息。

0
投票
所暗示的那样 @lig在这里。以下是如何使用子集模式对其进行建模:


对话框集合:

{ _id : ...., // dialog Id 'private' : 0 // is the conversation private 'participants' : [1, 3, 5, 6], //people who are in the conversation 'messages' :[ // Most recent messages embedded here (example: latest 100 messages) { 'mid' : ...// id of a message 'pid': 1, // person who wrote a message 'msg' : 'How are you doing?' //message }, .... { 'mid' : ...// id of a message 'pid': 2, // person who wrote a message 'msg' : 'I am fine buddy!' //message } ] }

注意,这与以前相同,只是我们不像以前那样将所有消息嵌入对话集合中,我们只嵌入它们的子集(最新的)并将所有较旧的消息(包括最新的消息)存储在自己的集合中 - 消息集合 - 如下所示:

留言收集:

{ 'mid' : ...// id of a message 'pid': 1, // person who wrote a message 'msg' : 'How are you doing?' //message }

通过仅将最常访问的消息直接保留在对话文档中,我们减少了工作集并提高了性能。与此同时,较旧的消息安静地驻留在它们自己的集合中,随时可以在需要时获取。使用子集模式时我们必须做出的一个权衡是我们必须管理子集,而且如果我们需要提取较旧的评论或所有信息,则需要额外访问数据库才能完成此操作。

其他资源:

我在这里写了一篇关于使用子集模式的文章:

https://medium.com/@desai.ashique/data-modelling-for-many-to-many-relationship-in-mongodb-48f1c80910b7

有关子集模式的 MongoDB 博客:

https://www.mongodb.com/blog/post/building-with-patterns-the-subset-pattern

© www.soinside.com 2019 - 2024. All rights reserved.