PHP操作MongoDB时的整数问题及对策说明


Posted in PHP onMay 02, 2011

MongoDB本身有两种整数类型,分别是:32位整数和64位整数,但旧版的PHP驱动不管操作系统是32位还是64位,把所有整数都当做32位整数处理,结果导致64位整数被截断。为了在尽可能保持兼容性的前提下解决这个问题,新版PHP驱动加入了mongo.native-long选项,以期在64位操作系统中把整数都当做64位来处理,有兴趣的可参考:64-bit integers in MongoDB

那么PHP驱动真的完全解决了整数问题么?NO!在处理group操作的时候还有BUG

为了说明问题,我们先来生成一些测试数据:

<?php 
ini_set('mongo.native_long', 1); 
$instance = new Mongo(); 
$instance = $instance->selectCollection('test', 'test'); 
for ($i = 0; $i < 10; $i++) { 
$instance->insert(array( 
'group_id' => rand(1, 5), 
'count' => rand(1, 5), 
)); 
} 
?>

下面让我们使用group操作,根据group_id分组,汇总计算count:
<?php 
ini_set('mongo.native_long', 1); 
$instance = new Mongo(); 
$instance = $instance->selectCollection('test', 'test'); 
$keys = array('group_id' => 1); 
$initial = array('count' => 0); 
$reduce = ' 
function(obj, prev) { 
prev.count += obj.count; 
} 
'; 
$result = $instance->group($keys, $initial, $reduce); 
var_dump($result); 
?>

结果和预想的有出入,count没有实现累加,而是变成了[object Object],目前,如果必须使用group操作,那么有两种方法可以缓解这个问题:
ini_set('mongo.native_long', 0); 
$initial = array('count' => (float)0);

这两种方法都是治标不治本的权宜之计,既然当前PHP驱动里group的实现有问题,那我们就绕开它,用其它的方式实现同样的功能,这个方式就是MapReduce
<?php 
ini_set('mongo.native_long', 1); 
$instance = new Mongo(); 
$instance = $instance->selectDB('test'); 
$map = ' 
function() { 
emit(this.group_id, this.count); 
} 
'; 
$reduce = ' 
function(key, values) { 
var sum = 0; 
for (var index in values) { 
sum += values[index]; 
} 
return sum; 
} 
'; 
$result = $instance->command(array( 
'mapreduce' => 'test', 
'map' => $map, 
'reduce' => $reduce 
)); 
$result = iterator_to_array($instance->{$result['result']}->find()); 
var_dump($result); 
?>

把大象放冰箱里需要三步,而使用MapReduce仅仅需要Map和Reduce两步即可,这里有一个PDF文档生动的说明了MySQL中GROUP BY和MongoDB中MapReduce的对应关系:

PHP操作MongoDB时的整数问题及对策说明 

SQL to MongoDB

此外,还有很多资料可供参考,如:MongoDB Aggregation III: Map-Reduce Basics

说明:软件版本为MongoDB(1.6.5),PECL Mongo(1.1.4)。不同版本结论可能不同。

PHP 相关文章推荐
实用函数8
Nov 08 PHP
使用VisualStudio开发php的图文设置方法
Aug 21 PHP
php源代码安装常见错误与解决办法分享
May 28 PHP
PHP curl 获取响应的状态码的方法
Jan 13 PHP
php 判断服务器操作系统的类型
Feb 17 PHP
Laravel 4 初级教程之安装及入门
Oct 30 PHP
thinkphp在低版本Nginx 下支持PATHINFO的方法分享
May 27 PHP
Yii控制器中操作视图js的方法
Jul 04 PHP
php版微信发红包接口用法示例
Sep 23 PHP
PHP使用Redis长连接的方法详解
Feb 12 PHP
Yii框架实现对数据库的CURD操作示例
Sep 03 PHP
Laravel框架控制器,视图及模型操作图文详解
Dec 04 PHP
php HandlerSocket的使用
May 02 #PHP
深入理解PHP原理之错误抑制与内嵌HTML分析
May 02 #PHP
PHP错误抑制符(@)导致引用传参失败Bug的分析
May 02 #PHP
一些PHP Coding Tips(php小技巧)[2011/04/02最后更新]
May 02 #PHP
PHP中使用gettext来支持多语言的方法
May 02 #PHP
php中神奇的fastcgi_finish_request
May 02 #PHP
PHP开发不能违背的安全规则 过滤用户输入
May 01 #PHP
You might like
用IE远程创建Mysql数据库的简易程序
2006/10/09 PHP
据说是雅虎的一份PHP面试题附答案
2009/01/07 PHP
php输出xml属性的方法
2015/03/19 PHP
javascript 打印页面代码
2009/03/24 Javascript
jquery 插件学习(五)
2012/08/06 Javascript
jQuery判断当前点击的是第几个li的代码
2014/09/26 Javascript
原生Ajax 和jQuery Ajax的区别示例分析
2014/12/17 Javascript
vuejs2.0实现分页组件使用$emit进行事件监听数据传递的方法
2017/02/22 Javascript
轻松理解JavaScript之AJAX
2017/03/15 Javascript
JS实现按钮控制计时开始和停止功能
2017/07/27 Javascript
Vuejs 2.0 子组件访问/调用父组件的方法(示例代码)
2018/02/08 Javascript
vue3.0 CLI - 2.4 - 新组件 Forms.vue 中学习表单
2018/09/14 Javascript
vue自定义指令之面板拖拽的实现
2019/04/14 Javascript
Vue学习之常用指令实例详解
2020/01/06 Javascript
[01:00:04]DOTA2上海特级锦标赛B组小组赛#1 Alliance VS Spirit第二局
2016/02/26 DOTA
python实现在pickling的时候压缩的方法
2014/09/25 Python
玩转python爬虫之URLError异常处理
2016/02/17 Python
python的pdb调试命令的命令整理及实例
2017/07/12 Python
Python方法的延迟加载的示例代码
2017/12/18 Python
Python中optparser库用法实例详解
2018/01/26 Python
python中format()函数的简单使用教程
2018/03/14 Python
Python开发的十个小贴士和技巧及长常犯错误
2018/09/27 Python
对Django中的权限和分组管理实例讲解
2019/08/16 Python
Numpy 中的矩阵求逆实例
2019/08/26 Python
使用python和pygame制作挡板弹球游戏
2019/12/03 Python
.dcm格式文件软件读取及python处理详解
2020/01/16 Python
python爬虫实例之获取动漫截图
2020/05/31 Python
Python 中如何使用 virtualenv 管理虚拟环境
2021/01/21 Python
教师专业自荐书范文
2014/02/10 职场文书
合同协议书格式
2014/04/18 职场文书
审计局班子四风对照检查材料思想汇报
2014/10/07 职场文书
购房委托书
2014/10/15 职场文书
2015年行政助理工作总结
2015/04/30 职场文书
美丽人生观后感
2015/06/03 职场文书
iPhone13再次曝光
2021/04/15 数码科技
Redis数据结构之链表与字典的使用
2021/05/11 Redis