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

时间:2010-11-15 01:41:33

标签: mongodb database-design non-relational-database nosql

假设您有大量用户(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),其中包含一些可能的截止日期优化,允许标记全部读取以擦除数据库并重新开始知道该日期之前的任何内容都是“已读”。

那么,MongoDB / NOSQL专家,你在实践中看到了什么方法来解决这个问题,以及它们是如何运作的?

2 个答案:

答案 0 :(得分:5)

{
_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和upsert创建prefs对象它进入MongoDB。如果你想要更多的灵活性(比如说标签或文件夹),你可能想要为每个收件人制作一个pref。例如,您可以添加:

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

到prefs对象,然后获取用'tech stuff'标记的所有消息的所有prefs,你会得到类似的东西:

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

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

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

如果你想做一些事情,比如计算每个'标签'有效包含多少条消息,这可能有点棘手。如果它只是少数几个标签,您只需在查询结尾为每个查询添加.count()即可。如果它是数百或数千,那么您可以使用map / reduce服务器端脚本或者可以跟踪每个用户的每个标记的消息计数的对象。

答案 1 :(得分:3)

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

{
  _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数组,就不可能实现这一点,因此每个用户都包含在每个文档(或连接表)中,但这会产生很大的存储成本。 / p>