MongoDB $установить не обновляющуюся запись


Я экспериментирую с MongoDB, используя расширение PHP PECL, однако у меня возникают трудности с получением определенного запроса на обновление для работы. Я искал ответы на 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. Я основываю свой запрос на сопоставлении, показанном в нижней части SQL для Монго Чита Лист в руководстве по PHP

Здесь я хочу обновить поле 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. Я уверен, что это очевидно, и мне просто нужна вторая пара глаз на это.

Большое спасибо.

 12
Author: Leigh, 2012-02-15

4 answers

Я провел несколько исследований, чтобы понять, почему это происходит. И я не думаю, что смогу найти способ "исправить" эту проблему.

В 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);
?>
 11
Author: Derick, 2012-03-06 13:26:17

После выполнения различных тестов, основанных на комментарии 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);

Немного погуглив и прочитав некоторые документы PHP Mongo, я обнаружил, что могу использовать объекты вместо массивов. Поэтому я попробовал это:

$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 не обновляется.

Я думаю, что собираюсь отправить отчет об ошибке.

 9
Author: Leigh, 2012-02-16 10:28:10

Вы не можете использовать число в качестве допустимого имени поля в mongodb. Попробуйте поместить свое поле "0" в кавычки, как это реализовано на самом деле.

 0
Author: nnythm, 2012-02-16 01:16:59
we can update record in mongo db using php example below:-
$_REQUEST['pfid'] = 'xxxxxxx' //put id in which u want to update
$m = new MongoClient(<putconnection>);
   echo "Connection to database successfully";
     $db = $m->unified;
      $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);
 -1
Author: manoj tiwari, 2018-05-03 06:38:52