Ian*_*cer 13 database-design non-relational-database mongodb nosql
假设您有大量用户(M)和大量文档(N),并且您希望每个用户能够将每个文档标记为已读或未读(就像任何电子邮件系统一样).在MongoDB中表示这个的最佳方法是什么?还是其他任何文件数据库?
StackOverflow上有几个问题问关系数据库这个问题,但是我没有看到任何关于文档数据库的建议:
通常,答案涉及一个列出用户已读取的所有内容的表:(即用户ID元组,文档ID),其中包含一些可能的截止日期优化,允许标记全部读取以擦除数据库并重新开始知道任何内容在该日期之前是'读'.
那么,MongoDB/NOSQL专家,你在实践中看到了什么方法来解决这个问题,它们是如何运作的?
{
_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]
}
Run Code Online (Sandbox Code Playgroud)
假设您有3条消息要检索首选项,您可以通过以下方式获取它们:
db.messages.find({
messageId : { $in : [messageId1,messageId2,messageId3]},
ownerId: receipientId,
type:'prefs'
})
Run Code Online (Sandbox Code Playgroud)
如果您只需要读取/未读取,则可以将其与MongoDB的upsert功能一起使用,因此您不会为每条消息创建prefs,除非用户实际读取它,然后基本上您创建具有您自己的唯一ID的prefs对象并将其插入MongoDB .如果你想要更多的灵活性(比如说标签或文件夹),你可能想要为每个收件人制作一个pref.例如,您可以添加:
tags: ['inbox','tech stuff']
Run Code Online (Sandbox Code Playgroud)
到prefs对象,然后得到所有标记为'tech stuff'的消息的所有prefs你会像:
db.messages.find({type: 'prefs', ownerId: recipientId, tags: 'tech stuff'})
Run Code Online (Sandbox Code Playgroud)
然后,您可以使用在prefs中找到的messageIds来查询和查找对应的所有消息:
db.messages.find((type:'message', _id: { $in : [array of messageIds from prefs]}})
Run Code Online (Sandbox Code Playgroud)
如果你想做一些事情,比如计算每个"标签"有效包含多少条消息,这可能有点棘手.如果它只是少数几个标签,您可以.count()
在查询结尾添加每个查询.如果它是数百或数千,那么您可以使用map/reduce服务器端脚本或者可以跟踪每个用户的每个标记的消息计数的对象.
小智 5
如果您只存储一个简单的布尔值,如已读/未读,另一种方法是在每个文档中嵌入一个数组,其中包含已阅读用户的列表。
{
_id: 'document#42',
...
read_by: ['user#83', 'user#2702']
}
Run Code Online (Sandbox Code Playgroud)
然后,您应该能够索引该字段,从而快速查询 Documents-read-by-User 和 Users-who-read-Document。
db.documents.find({read_by: 'user#83'})
db.documents.find({_id: 'document#42}, {read_by: 1})
Run Code Online (Sandbox Code Playgroud)
然而,我发现,我通常查询那些所有文件不能被读取特定用户,我想不出任何解决方案,可以利用指数在这种情况下。我怀疑如果没有数组read_by
和unread_by
数组就不可能做到这一点,因此每个用户都包含在每个文档(或连接表)中,但这会产生很大的存储成本。