Подтвердить что ты не робот

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 to Mongo Cheat Sheet в руководстве по 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. Я уверен, что это очевидно, и мне просто нужна вторая пара глаз.

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

4b9b3361

Ответ 1

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

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);
?>

Ответ 2

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

ЭТО РАБОТЫ!

Но я не смог выяснить, почему...

Edit:

Проникновение через исходный код расширения mongo

Метод MongoCollection->update выполняет следующее: buf уже является указателем, а newobj - zval (второй параметр запроса). HASH_P просто возвращает свойство right для 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 не обновляется.

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

Ответ 3

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

Ответ 4

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