Mongodb nodejs mapreduce

时间:2014-12-04 14:31:24

标签: node.js mongodb mapreduce aggregation-framework

我有一个包含以下数据的集合

{
    id:1,
    uid:'a1',
    cat:'main',
    subject:'Hello',
},
{
    id:2,
    uid:'a1',
    cat:'a'
},
{
    id:3,
    uid:'a1',
    cat:'b'
},

在上面的集合中我想搜索{ cat:'main' }并希望获得以下结构中的记录

[{
id:1,
uid:'a1',
category:'main',
subject:'Hello',
},
{
id:2,
uid:'a1',
category:'a',
subject:'Hello'
},
{
id:3,
uid:'a1',
category:'b',
subject:'Hello'
}]

所以我正在尝试搜索subject仅出现在类别main中的集合,然后我必须获得与类别{{1}具有相同uid的其他记录}}。

这是否可以使用mapReduce?

1 个答案:

答案 0 :(得分:0)

使用聚合管道有两种方法可以做到这一点。不需要Map-reduce功能。

第一种方法基于这样的假设:类别main的文档将始终插入到同一uid的其他文档之前,并且总是比其他文档的id小一些拥有相同的uid。如果在插入文档时注意这一点,我们可以根据id字段进行排序,并对其进行索引。

  • Sort基于索引字段。
  • {li> Group位于uid字段。所以每组的第一条记录将是 main类别记录。
  • Match仅限具有main类别记录的组。
  • Unwind每组中的所有记录并应用主题 第一条记录到每组中的所有记录。

守则:

collection.aggregate([
{$sort:{"id":1}},
{$group:{"_id":"$uid",
         "cat":{$first:"$cat"},
         "subject":{$first:"$subject"},
         "record":{$push:"$$ROOT"}}},
{$match:{"cat":"main"}},
{$unwind:"$record"},
{$project:{"_id":0,
           "id":"$record.id",
           "uid":"$_id",
           "cat":"$record.cat",
           "subject":"$subject"}}
],function(err,resp){
  console.log(resp);
 })

第二种方法是对您提供的简单示例的粗暴实现,这可能会变成较小的表现者。

需要额外的投影操作符来识别每个组的main类别记录。我们根据这个预计的领域进行排序。剩下的逻辑是一样的。

db.collection.aggregate([
{$project:{"_id":0,
           "id":1,"uid":1,"cat":1,"subject":1,
           "isMainRecord":{$cond:[{$eq:["$cat","main"]},0,1]}}},
{$sort:{"isMainRecord":1}},
{$group:{"_id":"$uid",
         "cat":{$first:"$cat"},"subject":{$first:"$subject"},
         "record":{$push:"$$ROOT"}}},
{$match:{"cat":"main"}},
{$unwind:"$record"},
{$project:{"_id":0,"id":"$record.id",
           "uid":"$_id","cat":"$record.cat","subject":"$subject"}}
],{allowDiskUse:true},function(err,resp){
 console.log(resp);
})