我有这个架构来支持站内消息传递:
当我向另一个成员发送消息时,该消息将保存到消息表中;将一条记录添加到MessageSent表中,并将每个收件人的记录添加到MessageInbox表中。 MessageCount用于跟踪收件箱/发送文件夹中的邮件数量,并使用MessageInbox / MessageSent上的插入/删除触发器填充 - 这样我总是可以知道成员有多少邮件而没有进行昂贵的“选择计数”( *)“查询。
此外,当我查询成员的消息时,我加入到成员表中以获取成员的FirstName / LastName。
现在,我将把应用程序移动到MongoDB,我不太确定应该是什么样的集合架构。因为MongoDB中没有可用的连接,所以我必须对其进行完全非规范化,因此我需要MessageInbox,MessageDraft和MessageSent集合以及完整的消息信息,对吧?
然后我不确定要关注:
如果用户更改了他的First / LastName怎么办?它将作为发件人在某些消息中存储为非规范化,作为其他消息中的收件人的一部分 - 如何以最佳方式更新它?
如何获取消息计数?同时会有大量的请求,所以它必须表现良好。
非常感谢任何想法,意见和建议!
答案 0 :(得分:1)
我可以为您提供一些见解,了解我在MongoDB中模拟JOIN的工作。
在这种情况下,我将相应用户(或多个用户)的ID存储在给定对象中,例如消息集合中的消息对象。
(我不建议这是你的架构,只是用它作为我的方法的一个例子)
{
_id: "msg1234",
from: "user1234",
to: "user5678",
subject: "This is the subject",
body: "This is the body"
}
我会查询数据库以获取我需要的所有消息然后在我的应用程序中我会迭代结果并构建一组用户ID。我会过滤此数组是唯一的,然后使用$in
运算符第二次查询数据库以查找给定数组中的任何用户。
然后在我的应用程序中,我将结果返回到对象。
它需要对数据库进行两次查询(或者如果你想加入其他集合,可能还需要更多),但这说明了很多人长期以来一直在倡导的东西:在你的应用层中加入你的JOIN。让数据库花时间查询数据,而不是处理数据。无论如何,您可以比数据库更快,更便宜地扩展应用程序服务器。
我正在使用此模式在我的应用程序中创建实时活动源,它可以完美无缺地运行。我更喜欢将非正规化的东西归结为可能像用户信息一样变化的东西,因为在写入数据库时,如果新数据不适合旧数据,MongoDB可能需要重写整个对象。如果我需要在我的数据库中重写数百(或数千)个活动项,那么这将是一场灾难。
此外,对MongoDB的写入是阻塞的,所以如果我刚才描述的情况发生,所有读取和写入都将被阻止,直到写入操作完成。我相信这个计划将以2.x系列的某些容量来解决,但它仍然不会是完美的。
另一方面,索引查询速度非常快,即使您需要执行其中两个查询来获取数据。