我使用MongoDB+PHP作为一个"facebookish"新闻提要,包含不同类型的提要(帖子、照片、民意调查等)和评论。
每个提要都属于某个"通道"-目前可能是用户或组(未来可能会有更多容器)。
任何用户都可以订阅任何频道或取消订阅。
现在让我们假设有大量的频道和大量的提要。频道/订阅源/评论的最佳结构是什么?
我正在考虑两种方法:
1)订阅源集合,每个订阅源中都有订阅者列表:
feeds:
[
{date_added: ...,
last_update: ...,
title: ...,
text: ...,
channel: ...,
channel_subscribers: [...],
comments_subscribers: [...],
comments: [...]
},
{...},
{...},
{...}
]
如果我想获得最后的提要:
db.feeds.find({date_added: "this week", channel_subscribers: "my_login"});
如果我想获得带有新评论的提要:
db.feeds.find({last_update: "this week", comments_subscribers: "my_login"});
优点:
- 简单快速的读数
缺点:
- 当我想订阅/取消订阅频道时,我必须运行浏览所有订阅源并从列表中推/拉我的名字channel_subscribers;如果我有大量的饲料,可能会很慢
2)单独的"通道"集合:同样的事情,但在信道集合中保留订户列表:
channels:
[
{channel_id:..., last_update: ..., subscribers: [...]},
{channel_id:..., last_update: ..., subscribers: [...]}
]
首先,我必须查询最近更新的频道:
subscribes = db.channels.find({last_update: "today", subscribers: "my_login"})
现在找到我的订阅源:
db.feeds.find({channel: {$in: subscribes}], date_added: "today"})
优点:
- 简单、快速、更安全的订阅/取消订阅
缺点:
- 我觉得我应该避免中的$,因为它很慢(?),尤其是当我有很多订阅了放置在此运算符内部
3)在用户集合中保留用户订阅(因此每个用户都有自己的订阅数组)
users:
[
{_id: ..., login: ..., email: ..., subscribes: [...]}
]
缺点:-在这种情况下,我们将在$in中放入比以前(#2)方法更大的数组。
4)你的建议
好的,我自己回答。我试着在我的笔记本电脑Windows 7 32位/2GB RAM上进行测试。我创建了一个"提要"集合,并在其中填充了500个提要:
feeds:
[
{_id: ..., subscribers: [...]},
{_id: ..., subscribers: [...]},
]
每个"订阅者"数组都有一个包含2000个短随机字符串名称的列表。
首先,我必须提到我的数据库从60Mb增加到1.5Gb。
然后,当我运行shell命令db.feeds.ensureIndex({subscribers: 1})
时,它挂起了大约3分钟,然后停止,并出现错误:"can't map file memory - mongo requires 64 bit build for larger datasets"
。
因此,在mongo的文档中创建如此大的多关键字字段绝对不是一个好主意。