MongoDB聚合框架

时间:2013-07-14 13:06:16

标签: mongodb

我的文档结构如下:

{
  '_id' => 'Star Wars',
  'count' => 1234,
  'spelling' => [ ( 'Star wars' => 10, 'Star Wars' => 15, 'sTaR WaRs' => 5) ]
}

我想获得前N个文档(通过递减计数),但每个文档只有一个拼写(具有最高值的文档)。有没有办法用聚合框架来做到这一点?

我可以轻松获得前10名结果(使用$ sort和$ limit)。但是,我如何才能获得每个拼写一次?

例如,如果我有以下三个记录:

{
  '_id' => 'star_wars',
  'count' => 1234,
  'spelling' => [ ( 'Star wars' => 10, 'Star Wars' => 15, 'sTaR WaRs' => 5) ]
}
{
  '_id' => 'willow',
  'count' => 2211,
  'spelling' => [ ( 'willow' => 300, 'Willow' => 550) ]
}
{
  '_id' => 'indiana_jones',
  'count' => 12,
  'spelling' => [ ( 'indiana Jones' => 10, 'Indiana Jones' => 25, 'indiana jones' => 5) ]
}

我要求排名前2的结果,我会得到:

{
  '_id' => 'willow',
  'count' => 2211,
  'spelling' => 'Willow'
}
{
  '_id' => 'star_wars',
  'count' => 1234,
  'spelling' => 'Star Wars'
}

(或其他相似之处)

谢谢!

1 个答案:

答案 0 :(得分:2)

您使用对象的键作为值时,您设计的架构会使使用除MapReduce之外的任何内容变得困难。因此,我调整了您的架构以更好地匹配MongoDB的功能(在本例中也采用JSON格式):

{
  '_id' : 'star_wars',
  'count' : 1234,
  'spellings' : [ 
    { spelling: 'Star wars', total: 10}, 
    { spelling: 'Star Wars', total : 15}, 
    { spelling: 'sTaR WaRs', total : 5} ]
}

请注意,它现在是一个具有特定键名spelling的对象数组,以及total的值(我不知道该数字实际代表的是什么,所以我调用了它在我的例子中总计。)

进入聚合:

db.so.aggregate([
    { $unwind: '$spellings' }, 
    { $project: { 
        'spelling' : '$spellings.spelling', 
        'total': '$spellings.total', 
        'count': '$count'  
        }
    }, 
    { $sort : { total : -1 } }, 
    { $group : { _id : '$_id',
        count: { $first: '$count' },
        largest : { $first : '$total' },
        spelling : { $first: '$spelling' }
        }
    }
])
  1. 展开所有数据,以便聚合管道可以访问数组的各种值
  2. 展平数据以包含管道所需的关键方面。在这种情况下,特定spellingtotalcount
  3. total进行排序,以便最后一次分组可以使用$first
  4. 然后,进行分组,以便仅返回每个$first的{​​{1}}值,然后还返回_id,因为它为管道展平,每个临时文档将包含count字段。
  5. 结果:

    count