在php中需要mongo的地图缩小功能
这是我的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函数。
答案 0 :(得分:3)
调用emit()
时,第一个参数是您要减少的键(或者为此示例分组)。第二个参数是为该键发出的值,可以是任何值。对于您的示例,您可能意味着使用文档的ID作为关键字,在news
字段中发出所有值的总和:
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(),了解上述示例中该方法调用背后的原因。
答案 1 :(得分:1)
虽然jmikola的回答让我可以直接处理mongo map reduce函数。
我正在添加此答案,以帮助未来的访问者。
以下map-reduce
功能完全符合我的要求。
这将通过添加(news
)将新闻字段中的所有值汇总到命令中创建的名为"out" => "news"
的新集合。
地图缩减功能
$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
)