MongoDB $设置不更新记录

时间:2012-02-15 16:47:33

标签: php mongodb

我正在使用PHP PECL扩展试验MongoDB,但是我很难获得某个更新查询。我在SO上搜索了一些运气不大的答案。

我创建了一个基本的集合:

$m = new Mongo;
$collection = $m->testdb->testcollection;

$collection->insert(array(
    0, 1, 1, 2, 3, 5
));

使用findOnevar_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。我确定这很明显,我只需要第二双眼睛。

非常感谢。

4 个答案:

答案 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
);

是否有效,字段01均未更新。

我想我要提交错误报告。

答案 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);