代码之家  ›  专栏  ›  技术社区  ›  Ian Mercer

MongoDB/NOSQL:处理消息的读/未读状态的最佳方法

  •  13
  • Ian Mercer  · 技术社区  · 15 年前

    假设您有大量用户(M)和大量文档(N),并且希望每个用户都能够将每个文档标记为已读或未读(就像任何电子邮件系统一样)。在MongoDB中最好的方式是什么?或者其他文档数据库?

    StackOverflow上有几个问题问关系数据库这个问题,但是我没有看到任何关于文档数据库的建议:

    What's the most efficient way to remember read/unread status across multiple items?

    Implementing an efficient system of "unread comments" counters

    通常情况下,答案包含一个表,其中列出了用户所读的所有内容:(即用户id、文档id的元组)以及对截止日期的一些可能的优化,允许将all标记为read,以擦除数据库并重新开始,知道该日期之前的任何内容都是“read”。

    那么,MongoDB/NOSQL专家们,您在实践中看到了哪些解决这个问题的方法,它们是如何执行的?

    2 回复  |  直到 8 年前
        1
  •  6
  •   Klinky    15 年前
    {
    _id: messagePrefs_uniqueId,
    type: 'prefs',
    timestamp: unix_timestamp
    ownerId: receipientId,
    messageId: messageId,
    read: true / false,
    }
    
    {
    _id: message_uniqueId,
    timestamp: unix_timestamp
    type: 'message',
    contents: 'this is the message',
    senderId: senderId,
    recipients: [receipientId1,receipientId2]
    }
    

    假设您有3条要检索首选项的消息,您可以通过以下方式获取它们:

    db.messages.find({
    messageId : { $in : [messageId1,messageId2,messageId3]},
    ownerId: receipientId, 
    type:'prefs'
    })
    

    如果您所需要的只是读/未读,您可以将其与MongoDB的upsert功能一起使用,因此除非用户实际阅读了每条消息,否则您不会为每条消息创建prefs,然后基本上您使用自己的唯一id创建prefs对象,并将其upsert到MongoDB中。如果你想要更多的灵活性(比如说标签或文件夹),你可能想要为每个消息接收者做PREF。例如,您可以添加:

    tags: ['inbox','tech stuff']
    

    到prefs对象,然后要获取所有标记有“tech stuff”的邮件的所有prefs,您可以执行以下操作:

    db.messages.find({type: 'prefs', ownerId: recipientId, tags: 'tech stuff'})
    

    然后,您可以使用在prefs中找到的消息id来查询和查找所有对应的消息:

    db.messages.find((type:'message', _id: { $in : [array of messageIds from prefs]}})
    

    如果你想做一些事情,比如计算每个“标记”有效包含的消息数量,这可能会有点棘手。如果只是几个标签,你可以添加 .count() 在每个查询的查询结束时。如果是成百上千个,那么使用map/reduce服务器端脚本或者跟踪每个用户每个标记的消息计数的对象可能会做得更好。

        2
  •  4
  •   code_monkey_steve    8 年前

    如果只存储一个简单的布尔值(如read/unread),另一种方法是在每个文档中嵌入一个数组,该数组包含已读用户的列表。

    {
      _id: 'document#42',
      ...
      read_by: ['user#83', 'user#2702']
    }
    

    然后,您应该能够索引该字段,以便快速查询由用户和读取文档的用户读取的文档。

    db.documents.find({read_by: 'user#83'})
    
    db.documents.find({_id: 'document#42}, {read_by: 1})
    

    但是,我发现我经常查询 已经被一个特定的用户读过了,在这种情况下,我想不出任何可以使用索引的解决方案。我想不同时拥有这两样东西是不可能做到这么快的 read_by unread_by 数组,这样每个用户都包含在每个文档(或联接表)中,但这将有很大的存储成本。

    推荐文章