15

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

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

跨多个项目记住已读/未读状态的最有效方法是什么?

实施有效的“未读评论”计数器系统

通常,答案涉及列出用户已阅读的所有内容的表格:(即用户 id 的元组,文档 id)以及对截止日期的一些可能的优化,允许将所有内容标记为已读以擦除数据库并重新开始知道任何事情在该日期之前是“已读”。

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

4

2 回答 2

6
{
_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 功能一起使用,因此除非用户实际阅读它,否则您不会为每条消息创建首选项,然后基本上您使用自己的唯一 ID 创建首选项对象并将其插入 MongoDB . 如果您想要更多的灵活性(例如标签或文件夹),您可能希望为每个邮件收件人设置首选项。例如,您可以添加:

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

到 prefs 对象,然后获取所有标记为“tech stuff”的消息的所有 prefs,你可以这样:

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

然后,您可以使用在首选项中找到的 messageIds 来查询并找到所有对应的消息:

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

如果您想做一些事情,比如计算每个“标签”有效包含多少消息,这可能会有点棘手。如果它只是少数标签,您可以.count()为每个查询添加到查询的末尾。如果它是数百或数千,那么您可能会使用 map/reduce 服务器端脚本或跟踪每个用户每个标签的消息计数的对象做得更好。

于 2010-11-15T02:43:02.490 回答
5

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

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

然后,您应该能够对该字段进行索引,从而对 Documents-read-by-User 和 Users-who-read-Document 进行快速查询。

db.documents.find({read_by: 'user#83'})

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

但是,我发现我通常会查询特定用户尚未读取的所有文档,并且在这种情况下我想不出任何可以利用索引的解决方案。我怀疑如果没有数组read_byunread_by数组就不可能做到这一点,因此每个用户都包含在每个文档(或连接表)中,但这会产生很大的存储成本。

于 2017-08-31T04:12:39.430 回答