MongoDB $设置不更新记录

Lei*_*igh 12 php mongodb

我正在使用PHP PECL扩展试验MongoDB,但是我很难获得某个更新查询.我在SO上寻找答案,但运气不佳.

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

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

$collection->insert(array(
    0, 1, 1, 2, 3, 5
));
Run Code Online (Sandbox Code Playgroud)

使用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
Run Code Online (Sandbox Code Playgroud)

当我想要使用更新时,问题就来了$set.我的查询基于PHP手册中SQL到Mongo Cheat Sheet的底部显示的映射

在这里,我想更新字段0到值100

$obj = $collection->findOne();

$collection->update(
    array('_id' => $obj['_id']),
    array('$set' => array(0 => 100))
);
Run Code Online (Sandbox Code Playgroud)

重新获取记录显示它保持不变.

我确实想知道我是否做错了_id,但是下面的更新查询确实有效,虽然用新值替换整个记录,而不是简单地更新一个字段.

$collection->update(
    array('_id' => $obj['_id']),
    array(0 => 100)
);
Run Code Online (Sandbox Code Playgroud)

对象转储:

array
  '_id' => 
    object(MongoId)[7]
      public '$id' => string '4f3bde65a1f7a0315b000000' (length=24)
  0 => int 100
Run Code Online (Sandbox Code Playgroud)

有人可以指出我做错了什么,以及如何正确使用$set.我确定它很明显,我只需要第二双眼睛.

非常感谢.

Der*_*ick 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);
?>


Lei*_*igh 9

进行各种测试的基础上,从注释后yi_H从和答案nnythm我发现以下.

在所有情况下,我使用这个通用代码:

$collection->update(
    array('_id' => $obj['_id']),
    array('$set' => $updateObj)
);
Run Code Online (Sandbox Code Playgroud)

以下内容根本不起作用:

  • $updateObj = array(0 => 100);
  • $updateObj = array('0' => 100);

这些工作:

  • $updateObj = array(1 => 100);
  • $updateObj = array('1' => 100);

经过一些谷歌搜索和阅读一些Mongo PHP文档后,我发现我可以使用对象而不是数组.所以我尝试了这个:

$updateObj = new stdClass;
$updateObj->{0} = 100;
Run Code Online (Sandbox Code Playgroud)

这个工作!

但我一直无法找出原因......

编辑:

通过mongo扩展源代码

MongoCollection->update方法执行以下操作,buf已经是指针,newobj是zval(查询的第二个参数).HASH_P只需返回zval的右侧属性进行编码,具体取决于它是数组还是对象.

zval_to_bson(buf, HASH_P(newobj), NO_PREP TSRMLS_CC)
Run Code Online (Sandbox Code Playgroud)

bson_encode功能执行以下操作,功能相同.buf指针和zval z.

zval_to_bson(&buf, HASH_P(z), 0 TSRMLS_CC);
Run Code Online (Sandbox Code Playgroud)

所以我进行了以下测试.

$updateObj = new stdClass;
$updateObj->{0} = 100;

$one = bson_encode($updateObj);

$updateObj = array(0 => 100);

$two = bson_encode($updateObj);

var_dump($one === $two);
Run Code Online (Sandbox Code Playgroud)

输出是 true

仍然0不知道为什么不在数组中的字段名称工作.

编辑2:

进一步的实验表明,当0更新中包含名称为的字段(仅限数组,对象很好)时,不会对任何字段执行更新

例:

$updateObj = array(
    '1' => 200
);
Run Code Online (Sandbox Code Playgroud)

工作,字段1更新.

$updateObj = array(
    '0' => 100,
    '1' => 200
);
Run Code Online (Sandbox Code Playgroud)

难道没有工作,没有现场01更新.

我想我要提交一份错误报告.