2014-12-04 159 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