Как и в консоли MongoDB в PHP для обновления документов определена функция update
. Она принимает, как минимум, два параметра:
критерий отбора документов, которые надо обновить, и новый документ, на который заменяются старые документы в выборке. Также можно определить третий необязательный параметр options
,
в котором можно установить семь свойств:
upsert: хранит булевое значение. Если равно true
, и документов для обновления не найдено,
то создается новый документ.
multiple: хранит булевое значение. Если равно true
, то обновляются все найденные документы.
fsync: принимает булевое значение. По умолчанию равно false
. Если значение равно true
,
то перед подтверждением удачного добавления данных в бд, они в обязательном порядке записываются на жесткий диск.
w: если равно 1, то можно проводить операции записи-удаления-обновления. Если равно 0, то подобные операции запрещены. По умолчанию равно 1
j: принимает булевое значение. По умолчанию равно false. Если значение равно true, то перед подтверждением удачного добавления данных в бд, они в обязательном порядке журналируются
wtimeout: указывает время в миллисекундах, которое сервер будет ожидать подтверждения обновления. По умолчанию равно 10000 миллисекунд
timeout: указывает время в миллисекундах, которое клиент будет ожидать ответ от базы данных
Итак, обновим документ:
$con = new MongoClient(); $collection= $con-> test-> persons; // критерий отбора документов, которые надо обновить $oldDocs=array("name"=> "Mark", "age" => 23); // новый документ $newDoc = array( "name" => "Mark", "age" => 29, "languages" => array("engish", "greek"), "company" => array( "name" => "Facebook", "year" => 2004 ) ); // дополнительные параметры обновления // если документы по критерию не найдены, то новый документ вставляется $option = array("upsert" => true); $collection -> update($oldDocs, $newDoc, $option); // проверяем замену $list = $collection->find(); while($document = $list-<getNext()) { print_r($document); } $con->close();
В данном случае мы находим все документы, где ключ "name" имеет значение "Mark, а ключ "age" - значение 23. И затем заменяем элемент выборки на
новый документ, передаваемый во втором параметре функции update
.
Как мы увидели, если опция upsert равна true, то при отсутствии документа для обновления в коллекцию добавляется новый документ. Этот тот случай, когда мы можем задействовать оператор $setOnInsert. Данный оператор служит для установки значения какого-либо поля. Например:
$con = new MongoClient(); $collection= $con-> test-> persons; // критерий отбора документов, которые надо обновить $oldDocs=array("name"=> "Mark", "age" => 23); $newDoc = array("$setInInsert" => array ("company" => array( "name" => "Facebook", "year" => 2004 ))); $option = array("upsert" => true); $collection -> update($oldDocs, $newDoc, $option); // проверяем замену $list = $collection->find(); while($document = $list-<getNext()) { print_r($document); } $con->close();
В итоге если функция update не найдет элемента для обновления, то в бд будет добавлен новый документ, для которого оператор
$setOnInsert
установит значение для ключа company.
Очень утомительно обновлять весь документ, если нам надо обновить все одно значение. Поэтому в этом случае лучше воспользоваться оператором $set:
$con = new MongoClient(); $collection= $con-> test-> persons; $oldDocs=array("name"=> "Mark", "age" => 29); // новое значение для поля age $newDoc = array ('$set' => array("age" => 30)); $option = array("upsert" => true); $collection -> update($oldDocs, $newDoc, $option); // проверяем замену $list = $collection->find(); while($document = $list-<getNext()) { print_r($document); } $con->close();
Так как в примере выше увеличивалось числовое значение поля age на единицу, то мы могли бы применить и другой оператор - $inc. Этот оператор увеличивает числовое значение на определенное количество. Применим вместо $set оператор $inc:
$con = new MongoClient(); $collection= $con-> test-> persons; $oldDocs=array("name"=> "Mark", "age" => 30); // новое значение для поля age $newDoc = array ('$inc' => array("age" => 5)); $option = array("upsert" => true); $collection -> update($oldDocs, $newDoc, $option); // проверяем замену $list = $collection->find(); while($document = $list-<getNext()) { print_r($document); } $con->close();
Выражение array ('$inc' => array("age" => 5));
увеличит значение age на 5 единиц.
Если оператор $set устанавливает значение поля, то оператор $unset удаляет его:
$con = new MongoClient(); $collection= $con-> test-> persons; $oldDocs=array("name"=> "Mark", "age" => 35); $forDelete = array ('$inc' => array("age" => 1)); $collection -> update($oldDocs, $forDelete);
Иногда требуется не изменить значение, а изменить ключ - переименовать поле. Для этого служит оператор $rename:
$con = new MongoClient(); $collection= $con-> test-> persons; $oldDocs=array("name"=> "Mark", "age" => 35); $forRename = array ('$rename' => array("name" => "first name")); $collection -> update($oldDocs, $forRename);
В данном случае поле name
переименовывается в first name
для первого элемента выборки.
Отдельно следует рассмотреть ряд операторов, которые нацелены на работу с полями-массивами. Например, для добавления в массив нового значения
используется оператор $push
. Такой элемент уже есть, то будет добавлен второй элемент с таким же значением. Однако если массив с таким ключом не определен в документе, то приложение выдаст ошибку.
Итак, добавим в массив languages новый элемент:
$con = new MongoClient(); $collection= $con-> test-> persons; $oldDoc=array("name"=> "Mark", "age" => 35); $newElem = array ('$push' => array("languages" => "spanish")); $collection -> update($oldDoc, $newElem);
Здесь добавляется одно новое значение - spanish - в массив languages. Однако у нас может возникнуть задача добавить сразу несколько значений
одним разом. В этом случае нам надо использовать в связке с оператором $push
оператор $each
:
$con = new MongoClient(); $collection= $con-> test-> persons; $oldDoc=array("name"=> "Mark", "age" => 35); $newElem = array ('$push' => array("languages" => array( '$each' => array("russian", "ukrainian")))); $collection -> update($oldDoc, $newElem);
$push замечательно добавляет новые данные, но опять же мы сталкиваемся с проблемой: если такое значение уже есть в массиве, то оператор $push добавит в массив его копию. Чтобы избежать дублирования элементов, стоит применять оператор $addToSet:
$con = new MongoClient(); $collection= $con-> test-> persons; $oldDoc=array("name"=> "Mark", "age" => 35); //добавление набора $newElem = array ('$addToSet' => array("languages" => array( '$each' => array("russian", "chinese")))); // добавление одиночного элемента // $newElem = array ('$addToSet' => array("languages" => "italian")); $collection -> update($oldDoc, $newElem);
Если для добавления в массив используется оператор $push
, то для удаления из массива - оператор $pop
. Данный
оператор может удалять либо первый элемент (если получает в качестве параметра число -1), либо последний элемент (тогда в качестве параметра
передаем число 1):
$con = new MongoClient(); $collection= $con-> test-> persons; $oldDoc=array("name"=> "Mark", "age" => 35); // удаляем первый элемент из массива languages $popElem = array ('$pop' => array("languages" => -1)); $collection -> update($oldDoc, $popElem);
Похожую функциональность предлагает оператор pull, только в отличие от $pop, он удаляет элемент со всеми повторами в массиве (например, мы могли добавить ранее дубликаты с помощью $push и теперь хотим их удалить). Например:
$con = new MongoClient(); $collection= $con-> test-> persons; $oldDoc=array("name"=> "Mark", "age" => 35); // удаляем все вхождения значения greek в массиве languages $delElem = array ('$pull' => array("languages" => "greek")); $collection -> update($oldDoc, $delElem);
Если нам надо удалить не одно, а несколько значений сразу, то мы можем применить оператор $pullAll:
$con = new MongoClient(); $collection= $con-> test-> persons; $oldDoc=array("name"=> "Mark", "age" => 35); // удаляем все вхождения значения greek в массиве languages $delElems = array ('$pullAll' => array("languages" => array("greek", "english"))); $collection -> update($oldDoc, $delElems);
Функция save служит для обновления/добавления элемента. Она принимает два параметра: ассоциативный массив значений, которые надо обновить, и объект options, задающий дополнительные опции для сохранения документа. Этот объект options может принимать следующие параметры:
fsync: принимает булевое значение. По умолчанию равно false
. Если значение равно true
,
то перед подтверждением удачного добавления данных в бд, они в обязательном порядке записываются на жесткий диск.
w: если равно 1, то можно проводить операции записи-удаления-обновления. Если равно 0, то подобные операции запрещены. По умолчанию равно 1
j: принимает булевое значение. По умолчанию равно false. Если значение равно true, то перед подтверждением удачного добавления данных в бд, они в обязательном порядке журналируются
wtimeout: указывает время в миллисекундах, которое сервер будет ожидать подтверждения обновления. По умолчанию равно 10000 миллисекунд
timeout: указывает время в миллисекундах, которое клиент будет ожидать ответ от базы данных
Используем функцию save
для добавления и обновления документа:
// создаем новый документ $newDoc = array( "name" => "Mark", "age" => 29, "languages" => array("engish", "greek"), "company" => array( "name" => "Facebook", "year" => 2004 ) ); // дополнительные параметры для добавления $options = array("fsync" => true); $con = new MongoClient(); $collection= $con-> test-> persons; // сохраняем документ $collection -> save($newDoc, $options); // документ сохранен, теперь изменим его свойство и обновим $newDoc["age"]=30; $collection -> save($newDoc, $options);
Драйвер php для mongodb также предоставляет еще одну функцию с возможностью обновления - функцию findAndModify
. Эта функция
обновляет один документ и возвращает результат в случае успешного обновления.
Эта функция может принимать четыре параметра:
query: определяет фильтр выборки. Если данный параметр не указан, то выборка включает все элементы коллекции, однако при этом будет обновляться всегда первый элемент выборки
update: определяет информацию, которая будет обновляться
fields: определяет поля документа, которые необходимо возвратить в качестве результата. И вне зависимости от
указанных полей всегда будет возвращаться как минимум одно поле - _id
options: определяет дополнительные опции для обновления
sort: сортирует выборку в определенном порядке
remove: удаляет документ, если равно true
update: обновляет документ, если равно true
new: если равно true
возвращает в качестве результата обновленный документ. Если равно
false
(как по умолчанию), то возвращает выбранный для обновления документ до его обновления
upsert: если равно true
то выполняет вставку документа в коллекцию, если выборка не нашла ни одного документа
для обновления
Посмотрим на примере:
// новый документ, на который будет обновляться старый $newDoc = array( "name" => "Pavel", "age" => 30, "languages" => array("engish"), "company" => array( "name" => "Vkontakte", "year" => 2007 ) ); // фильтр для выборки документов $oldDocs = array("name" => "Mark"); $con = new MongoClient(); $collection= $con-> test-> persons; // получаем ранее обновленный документ $updatedDocument = $collection -> findAndModify($oldDocs, $newDoc); // получаем значение поля name в ранее обновленном документе - Mark echo "<p>Предыдущее имя: " . $updatedDocument["name"] . "</p>"
Как вы видите, в данном контексте функция findAndModify
эквивалентна простой функции update
. Здесь также используются
два параметра. Но при этом мы также получаем документ в его состоянии до обновления со всеми его полями. Теперь же используем
дополнительные параметры:
// обновим значение одного свойства $forUpdate = array('$set'=>("name" => "Pavel")); // фильтр для выборки документов $oldDocs = array("name" => "Mark"); // дополнительные опции для обновлени $options = array ('new' => true); $con = new MongoClient(); $collection= $con-> test-> persons; // получаем ранее обновленный документ $updatedDocument = $collection -> findAndModify($oldDocs, $forUpdate, null, $options); print_r($updatedDocument);
Также как и в случае с функцией update, здесь мы можем применять различные операторы, например, $set
для установки одного поля.
В качестве дополнительного параметра $options = array ('new' => true)
указываем, что мы хотим возвратить именно обновленный документ,
а не который был до обновления. И поскольку параметр $fields мы не указываем, то его место в функции findAndModify занимает null
.