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
. Я уверен, что это очевидно, и мне просто нужна вторая пара глаз на это.
Большое спасибо.
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); ?>
После выполнения различных тестов, основанных на комментарии 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
не обновляется.
Я думаю, что собираюсь отправить отчет об ошибке.
Вы не можете использовать число в качестве допустимого имени поля в mongodb. Попробуйте поместить свое поле "0" в кавычки, как это реализовано на самом деле.
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);