选择将作者标记为“允许其他人查看该用户的评论”的消息

时间:2012-08-29 09:56:08

标签: mongodb mongodb-query nosql

我正在寻找某些项目的某些时候切换到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有多难?

另外,还有另外一个问题。如何从第一条消息中选择topicsdate中的所有字段? (类似于$elemMatch.messages.0.date

PS:额外的问题:我可以返回主题的消息数量吗? (实际上没有用PHP计算它们。只需计划MongoDB select语句)

此致

1 个答案:

答案 0 :(得分:1)

所有问题都可以通过随新版本的MongoDB(今天发布!)附带的新版Aggregation framework或多或少来解决。

但有一点需要注意:聚合仅适用于单个集合。在第一个问题中,如果要将来自用户集合的信息(特别是messages_can_be_seen_by_others标志)与主题集合中的信息(即消息)组合在一起,则需要使用Map / Reduce,事先做一个额外的查询来检查您是否希望该用户包含在以下查询中,或者只是将整个用户文档与主题一起存储,而不仅仅是名称。这是你不能用RDBMS做的事情,但是对于像MongoDB这样的基于文档的数据库,这是很常见的做法。

除此之外,所有问题都可以通过聚合解决。例如

  1. 选择一个主题,可以使用以下语法完成来自特定用户的所有消息:

    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'}}}
    )
    

    此查询将首先仅过滤与标题匹配的主题,然后展开消息(与组相对)消息,过滤特定用户,最后根据标题将消息分组回来。

  2. 查找所有主题标题及其第一条(最早)消息的日期:

    db.topics.aggregate(
        {'$unwind': '$topic_messages'}, 
        {'$sort': {'topic_messages.date' : 1}}, 
        {'$group': {'_id': '$topic_title', 
                    'first_date': {'$first': '$topic_messages.date' }
                   }
        }
    )
    
  3. 计算一个主题的所有消息(使用MongoDB,而不是php):

    db.topics.aggregate(
        {'$match': {'topic_title': 'Some Topic Title'}}, 
        {'$unwind': '$topic_messages'}, 
        {'$group': {'_id':'$topic_title', 'count': {$sum: 1}}}
    )
    
  4. 所以你看,聚合框架非常强大,甚至可以在分片集合上工作,只要你需要的所有信息都存储在一个集合中。