我正在使用PHP PECL扩展试验MongoDB,但是我很难获得某个更新查询。我在SO上搜索了一些运气不大的答案。
我创建了一个基本的集合:
$m = new Mongo;
$collection = $m->testdb->testcollection;
$collection->insert(array(
0, 1, 1, 2, 3, 5
));
使用findOne
和var_dump
记录显示如下:
array
'_id' =>
object(MongoId)[6]
public '$id' => string '4f3bde65a1f7a0315b000000' (length=24)
0 => int 0
1 => int 1
2 => int 1
3 => int 2
4 => int 3
5 => int 5
当我想使用$set
进行更新时,问题就出现了。我的查询基于PHP手册中SQL to Mongo Cheat Sheet底部显示的映射
我希望将字段0
更新为值100
$obj = $collection->findOne();
$collection->update(
array('_id' => $obj['_id']),
array('$set' => array(0 => 100))
);
重新获取记录显示保持不变。
我确实想知道我是否对_id
做错了,但是以下更新查询确实工作,虽然用新值替换整个记录,而不是简单地更新一个字段。
$collection->update(
array('_id' => $obj['_id']),
array(0 => 100)
);
对象转储:
array
'_id' =>
object(MongoId)[7]
public '$id' => string '4f3bde65a1f7a0315b000000' (length=24)
0 => int 100
有人可以指出我做错了什么,以及如何正确使用$set
。我确定这很明显,我只需要第二双眼睛。
非常感谢。
答案 0 :(得分:11)
我正在调查为什么会这样。而且我认为我无法找到解决这个问题的方法。
JavaScript在数组和关联数组/对象之间存在差异。 PHP具有数组和对象之间的区别。对于PHP,关联数组是一个数组,对于JavaScript,它是一个对象。
当PHP驱动程序需要将数组转换为JSON对象时,它会尝试确定数组是否为:具有从0开始的顺序编号键的普通数组;或关联数组。当前实现将任何具有顺序编号键的数组视为从0开始的正常数组。普通数组不包含键。这就是问题所在。在驱动程序看到正常数组的情况下,BSON中没有发送到服务器的字段名称信息,因此服务器无法更新字段。
我想不出一种在不破坏任何现有代码的情况下改变这种行为的方法。因此,如果您需要数字字段名,则必须使用stdClass对象作为“主文档”。或者,您可以将这些密钥推送到嵌入式文档中,然后更新:
<?php $m = new Mongo; $collection = $m->demo->testcollection; $collection->insert(array( "_id" => 'bug341', 'data' => array( 0, 1, 1, 2, 3, 5 ) )); $obj = $collection->findOne(); $update = array('data.0' => 'zero int'); $collection->update( array( '_id' => 'bug341' ), array( '$set' => $update ) ); $obj = $collection->findOne(); var_dump($obj); ?>
答案 1 :(得分:9)
在执行各种测试后,根据 yi_H 的评论和 nnythm 的回答,我找到了以下内容。
在所有情况下,我都使用这个通用代码:
$collection->update(
array('_id' => $obj['_id']),
array('$set' => $updateObj)
);
以下内容根本不起作用:
$updateObj = array(0 => 100);
$updateObj = array('0' => 100);
这些确实有效:
$updateObj = array(1 => 100);
$updateObj = array('1' => 100);
经过一些谷歌搜索和阅读一些Mongo PHP文档后,我发现我可以使用对象而不是数组。所以我尝试了这个:
$updateObj = new stdClass;
$updateObj->{0} = 100;
但我一直无法找到原因......
修改强>
浏览mongo扩展源代码
MongoCollection->update
方法执行以下操作,buf已经是指针,newobj是zval(查询的第二个参数)。 HASH_P
只返回zval的右侧属性进行编码,具体取决于它是数组还是对象。
zval_to_bson(buf, HASH_P(newobj), NO_PREP TSRMLS_CC)
bson_encode
函数执行以下操作,功能相同。 buf指针和zval z。
zval_to_bson(&buf, HASH_P(z), 0 TSRMLS_CC);
所以我进行了以下测试。
$updateObj = new stdClass;
$updateObj->{0} = 100;
$one = bson_encode($updateObj);
$updateObj = array(0 => 100);
$two = bson_encode($updateObj);
var_dump($one === $two);
输出为true
仍然不知道为什么0
不适用于数组中的字段名称。
编辑2:
进一步的实验表明,当更新中包含名称为0
的字段时(仅限数组,对象就可以了)不会对任何字段执行更新
示例:
$updateObj = array(
'1' => 200
);
作品,字段1
已更新。
$updateObj = array(
'0' => 100,
'1' => 200
);
不是否有效,字段0
或1
均未更新。
我想我要提交错误报告。
答案 2 :(得分:0)
您不能在mongodb中使用数字作为有效字段名称。尝试将字段“0”放在引号中,这就是它实际实现的方式。
答案 3 :(得分:-1)
we can update record in mongo db using php example below:-
$m = new MongoClient(<Put Replica set>); //PHP mongoclient function
echo "Connection to database successfully";
$db = $m->dbname; //put DB name
$collection = $db->profile;
$document = array(
"name" => $_REQUEST['name'],
"email" => $_REQUEST['email'],
"age" => $_REQUEST['age'],
"address" => $_REQUEST['address'],
"comment"=> $_REQUEST['comment']
);
// print_r($document); die;
//echo $_REQUEST['pfid'];
$filter=array('_id'=>new MongoID( $_REQUEST['pfid'] ));
$update=array('$set'=>$document);
$collection->update( $filter, $update);