0

在php中需要mongo的map reduce函数

这是我的 mongo 结构

[_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。

如何更正此函数以及如何将字段总和作为“新闻”的数组总和添加到原始集合(mycollection)?

我不熟悉 mongo 中的 map reduce 功能。

4

2 回答 2

3

调用 时emit(),第一个参数是您将要减少的键(或分组,对于本示例)。第二个参数是为该键发出的值,可以是任何值。news对于您的示例,您可能意味着使用文档的 ID 作为键来发出字段中所有值的总和:

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

在这种情况下,可以使用占位符 reduce 函数(因为每个发出的键都是唯一的,所以几乎不需要做任何缩减):

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

但是,正如我在Google Group 帖子中提到的,您最好使用纯 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 的需要,并且应该具有更高的性能。如果您可以使用 $incnews在每个文档修改字段时更新总和,那就更好了。上面的代码片段对于初始化集合中的字段仍然有用sum,或者如果事情与每个文档的增量不同步,则可以纠正任何漂移。

注意:请参阅文档中的snapshot()以了解上述示例中该方法调用背后的原因。

于 2012-06-12T23:45:50.583 回答
1

虽然 jmikola 的回答给了我处理 mongo map reduce 函数的正确轨道。

我添加这个答案是为了帮助未来的访客。

以下map-reduce功能完全符合我的要求。这会将新闻字段中的所有值加到news命令中创建的新集合中,方法是添加 ( "out" => "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的总和一起收集totalid

输出

[_id] => MongoId Object (
    [$id] => 4fd8993a13cfcd4e42000000
)
[value] => Array (
    [id] => 454
    [total] => 14
)
于 2012-10-10T11:03:54.970 回答