2014-12-04 81 views
1

我有一个集合具有以下数据的MongoDB的NodeJS的MapReduce

{ 
    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的集合中,然后我必须获取其他类别uidmain类别相同的记录。

这是可能的使用mapReduce?

回答

0

有两种方法可以使用聚合管道完成此操作。 Map-Reduce功能不是必需的。

第一种方法是基于一个假设,即与main类别文档将始终先于其他文件中插入相同uid,将永远有一个比其他文件较小id具有相同uid。如果在插入文档时注意到这一点,我们可以根据id字段进行排序,并将其编入索引。

  • Sort基于索引字段。
  • Groupuid字段。所以每个组的第一个记录将是 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); 
}) 
+0

非常感谢您的回复,我能按照你的第一个例子,但100万的测试记录时,我在比赛更多的属性,例如日期范围搜索与限制25结果,可以采取建立查询差不多4-5秒,我认为这是因为首先所有的记录都被排序,然后将组应用到所有1个记录?我对么 ?无论如何要优化这个? – Arian 2014-12-09 16:29:53

+0

是的。您可以按升序索引id字段并删除第一个排序操作。 – BatScream 2014-12-09 16:35:28