2012-06-11 98 views
0

減少蒙戈功能需要一張地圖由蒙戈在PHP減少功能需要一張地圖使用PHP

這是我的蒙戈結構

[_id] => MongoId Object (
    [$id] => 4fcf2f2313cfcd2454500000d 
) 
[id] => 454 
[table] => people 
[news] => Array (
    [03-06-2012] => 2 
    [04-06-2012] => 3 
    [05-06-2012] => 5 
    [06-06-2012] => 4 
) 

在這裏,我試圖總結數組新聞與下面的代碼,

$map = new MongoCode('function() { emit(this.news, 1); }'); 
    $reduce = new MongoCode('function(previous, current) { 
        var count = 0; 
        for (index in current) { 
         count = count + current[index]; 
        } 
        return count; 
       }'); 

    $sales = $db->command(array(
     'mapreduce' => 'mycollection', 
     'map' => $map, 
     'reduce' => $reduce, 
     'query' => array('table' => 'people'), 
     'out' => 'news' 
    )); 

    //pr($sales);exit; 

    $users = $db->selectCollection($sales['result'])->find(); 

    foreach ($users as $user) { 
     //echo "{$user['_id']} had {$user['value']} sale(s).\n"; 
     pr($user); 
    } 

pr($user)

Array 
(
    [_id] => Array 
    (
     [04-06-2012] => 0 
     [08-06-2012] => 2 
     [11-06-2012] => 6 
    ) 

    [value] => 39540 
) 

我在哪裏預期值將是8而不是39540.

我該如何糾正這個函數以及如何將字段總和作爲'news'的數組總和添加到原始集合(mycollection)中?

我不熟悉mongo中的地圖縮減功能。

回答

3

當調用emit()時,第一個參數是您將要減少的鍵(或本例中的分組)。第二個參數是爲該鍵發出的值,可以是任何值。對於你的榜樣,您可能意味着發出的所有值的總和在news領域,使用文檔的ID爲你的關鍵:

var map = function() { 
    var total = 0; 
    for (count in this.news) { 
     total += count; 
    } 
    emit(this._id, total); 
} 

在這種情況下,一個佔位符,減少功能都可以使用(因爲每個發射鍵將是獨一無二的,有非常小的減少做)是:

var reduce = function(key, values) { 
    var total = 0; 
    values.forEach(function(v) { total += v; }); 
    return total; 
} 

然而,正如我在Google Group post提到的,你可能會更好用純PHP這樣做:

$cursor = $collection->find(array(), array('news' => 1)); 
$cursor->snapshot(); 

foreach ($cursor as $document) { 
    $collection->update(
     array('_id' => $document['_id']), 
     array('$set' => array('sum' => array_sum($document['news']))), 
     array('multiple' => false) 
    ); 
} 

使用map/reduce,您仍然需要檢查其結果並更新記錄。這將避免需要通過Mongo來執行JavaScript,並且應該更高效。如果您可以使用$ inc來更新總和,因爲news字段在每個文檔的基礎上進行修改,那會更好。上述代碼段對於初始化集合中的sum字段仍然有用,或者如果事情與每個文檔增量不同步,則會糾正任何漂移。

注意:請參閱snapshot()在上述示例中的該方法調用背後的推理文檔。

+0

我也跟着用純suming PHP和工作克好。但我試圖得到與地圖減少,但新的集合輸出爲[[id] => MongoId對象( [$ id] => 4fd8993a13cfcd4e42000000 ) [value] => 0013-06-2012'原始新聞數組是'[news] => Array( [13-06-2012] => 1 )'。快照是否會提高性能? –

+0

如果您嘗試使用map/reduce計算總和,則該值應該是整數和。就你而言,看起來你正在發佈新聞日期而不是總和。我上面的例子演示瞭如何使用map和reduce函數來計算總和。關於你的第二個問題,我沒有意識到任何快照記錄的性能影響,但可以假設有一些輕微的開銷是合理的。 – jmikola

1

雖然jmikola的回答讓我很樂意處理mongo map reduce函數。

我在添加這個答案以幫助未來的訪問者。

以下map-reduce功能完全符合我的要求。 這會將新聞字段中的所有值總和爲通過添加("out" => "news")命令創建的名爲news的新集合。

的map-reduce功能

$map = new MongoCode('function() { 
      var total = 0; 
      for (count in this.news) { 
      total += this.news[count]; 
      } 
      emit(this._id, {id: this.id, total: total}); 
     }'); 
$reduce = new MongoCode('function(key, values) { 
      var result = {id: null, total: 0}; 
      values.forEach(function(v) { 
      result.id = v.id; 
      result.total = v.total; 
      }); 
      return result; 
     }'); 

$sales = $db->command(array(
    'mapreduce' => 'mycollection', // collection name 
    'map' => $map, 
    'reduce' => $reduce, 
    'query' => array('table' => 'people'), 
    "out" => "news" // new collection name 
)); 

結果將是news收集與和作爲total和實際文檔的id

輸出

[_id] => MongoId Object (
    [$id] => 4fd8993a13cfcd4e42000000 
) 
[value] => Array (
    [id] => 454 
    [total] => 14 
)