MongoDB 有 32 位 (Int32) 與 64 位 (Int64) 整數。舊版 PHP 驅動 (≤1.2) 無視作業系統位元,全部視為 Int32,導致 64 位整數截斷。新版驅動引入 mongo.native_long 選項:
ini_set('mongo.native_long', true); // 64 位系統啟用 Int64
<?php
ini_set('mongo.native_long', true);
$m = new MongoClient();
$c = $m->test->test;
// 測試資料
for ($i=0; $i<10; $i++) {
$c->insert(['group_id'=>rand(1,5), 'count'=>rand(1,5)]);
}
// Group 聚合
$keys = ['group_id'=>1];
$initial = ['count'=>0];
$reduce = 'function(obj, prev) { prev.count += obj.count; }';
$result = $c->group($keys, $initial, $reduce);
// 結果:count 變成 [object Object] 而非數字!
var_dump($result);
ini_set('mongo.native_long', false); 強制用 32 位/浮點數$initial = ['count' => 0.0]; 使用浮點數初始值<?php
ini_set('mongo.native_long', true);
$m = new MongoClient();
$db = $m->test;
$map = 'function() { emit(this.group_id, this.count); }';
$reduce = 'function(key, values) {
var sum = 0;
for (var i in values) sum += values[i];
return sum;
}';
$cmd = [
'mapreduce' => 'test',
'map' => $map,
'reduce' => $reduce,
'out' => ['inline' => 1] // 直接回傳結果
];
$result = $db->command($cmd);
foreach ($result['results'] as $r) {
echo "group_id: {$r['_id']}, total: {$r['value']}\n";
}
| SQL | MongoDB Group | MongoDB MapReduce |
|---|---|---|
| SELECT g, SUM(c) FROM t GROUP BY g | group({key:{g:1}}, {c:0}, reduce) | map: emit(g,c); reduce: sum(values) |
| HAVING SUM(c) > 100 | 不支援 | finalize: function(k,v){ if(v>100)return v; } |
| 效能 | 單執行緒、鎖表 | 可分片平行、支援增量 |
| Bug 狀態 | Group 有整數 Bug,MapReduce 正常 | |
MongoDB\Driver\Manager + MongoDB\Collection::aggregate()MongoDB\BSON\Int64$pipeline = [
['\$group' => ['_id' => '\$group_id', 'total' => ['\$sum' => '\$count']]]
];
$cursor = $collection->aggregate($pipeline);
foreach ($cursor as $doc) { var_dump($doc); }
composer require mongodb/mongodbgroup() 改寫為 aggregate()mongo.native_long 設定