我正在寻找某些项目的某些时候切换到MongoDB。要做到这一点,我需要测试它,知道我能做什么,不能做什么。
在阅读了一些有关MongoDB如何工作的书籍后,我必须说我对select
的实际工作方式有点困惑。
假设我有一个名为users
的集合:
{
user_name: string,
....,
....,
messages_can_be_seen_by_others: boolean
}
另外,我收集了topics
:
{
topic_title: string,
.....,
.....,
topic_messages:
[
{
user_name: string,
text: string,
date: DateTime
},
{
user_name: string,
text: string,
date: DateTime
}
]
.....
}
如何根据users
集合选择一个主题及其所有消息?
我的意思是,数据库不应返回由Person1
标记为messages_can_be_seen_by_others
的人true
写的邮件。
那么,我应该使用map / reduce,在获得所有结果后使用php
进行过滤,还是有其他我不知道的事情?
如果我应该使用map / reduce有多难?
另外,还有另外一个问题。如何从第一条消息中选择topics
和date
中的所有字段? (类似于$elemMatch.messages.0.date
)
PS:额外的问题:我可以返回主题的消息数量吗? (实际上没有用PHP计算它们。只需计划MongoDB select语句)
此致
答案 0 :(得分:1)
所有问题都可以通过随新版本的MongoDB(今天发布!)附带的新版Aggregation framework或多或少来解决。
但有一点需要注意:聚合仅适用于单个集合。在第一个问题中,如果要将来自用户集合的信息(特别是messages_can_be_seen_by_others
标志)与主题集合中的信息(即消息)组合在一起,则需要使用Map / Reduce,事先做一个额外的查询来检查您是否希望该用户包含在以下查询中,或者只是将整个用户文档与主题一起存储,而不仅仅是名称。这是你不能用RDBMS做的事情,但是对于像MongoDB这样的基于文档的数据库,这是很常见的做法。
除此之外,所有问题都可以通过聚合解决。例如
选择一个主题,可以使用以下语法完成来自特定用户的所有消息:
db.topics.aggregate(
{$match: {'topic_title':'Some Topic Title'}},
{$unwind: '$topic_messages'},
{$match: {'topic_messages.user_name': 'Some User Name'}},
{$group: {'_id':'$topic_title', 'messages': {$addToSet: '$topic_messages'}}}
)
此查询将首先仅过滤与标题匹配的主题,然后展开消息(与组相对)消息,过滤特定用户,最后根据标题将消息分组回来。
查找所有主题标题及其第一条(最早)消息的日期:
db.topics.aggregate(
{'$unwind': '$topic_messages'},
{'$sort': {'topic_messages.date' : 1}},
{'$group': {'_id': '$topic_title',
'first_date': {'$first': '$topic_messages.date' }
}
}
)
计算一个主题的所有消息(使用MongoDB,而不是php):
db.topics.aggregate(
{'$match': {'topic_title': 'Some Topic Title'}},
{'$unwind': '$topic_messages'},
{'$group': {'_id':'$topic_title', 'count': {$sum: 1}}}
)
所以你看,聚合框架非常强大,甚至可以在分片集合上工作,只要你需要的所有信息都存储在一个集合中。