UPDATE¶
Каждая операция UPDATE ограничена одной коллекцией, и имя коллекции не должно быть динамическим. В одном запросе AQL допускается только один оператор UPDATE для одной коллекции, и за ним не могут следовать операции чтения или записи, обращающиеся к той же коллекции, операции обхода или функции AQL, которые могут читать документы.
Нельзя обновлять системные атрибуты _id, _key и _rev, но можно обновлять атрибуты _from и _to.
Обновление документа изменяет номер ревизии документа (атрибут _rev) на генерируемое сервером значение.
Синтаксис¶
Для операции обновления существует два синтаксиса:
UPDATE document IN collection
UPDATE keyExpression WITH document IN collection Оба варианта могут опционально заканчиваться предложением OPTIONS { ... }.
collection должно содержать имя коллекции, в которой должен быть обновлен документ.
document должен быть объектом и содержать атрибуты и значения для обновления. Атрибуты, которые еще не существуют в хранимом документе, добавляются к нему. Существующие атрибуты устанавливаются в предоставленные значения атрибутов (за исключением неизменяемых атрибутов _id и _key и управляемого системой атрибута _rev). Операция оставляет нетронутыми другие существующие атрибуты, не указанные в document. Это отличает операцию UPDATE от операции REPLACE, которая затрагивает все атрибуты хранимого документа, а не только те, которые вы указали в операции.
Под-атрибуты рекурсивно объединяются по умолчанию, но вы можете позволить атрибутам верхнего уровня заменить существующие, отключив опцию mergeObjects.
UPDATE <document> IN <collection>¶
При использовании первого синтаксиса объект document должен иметь атрибут _key с ключом документа. Существующий документ с этим ключом обновляется атрибутами, предоставленными объектом document (за исключением системных атрибутов _id, _key и _rev).
Следующий запрос добавляет или обновляет атрибут name документа, идентифицированного ключом my_key в коллекции users. Ключ передается через атрибут _key наряду с другими атрибутами:
1 | |
Следующий запрос является некорректным, поскольку объект не содержит атрибута _key и поэтому невозможно определить обновляемый документ:
1 | |
Вы можете объединить операцию UPDATE с циклом FOR для определения необходимых ключевых атрибутов, как показано ниже:
1 2 | |
Обратите внимание, что операции UPDATE и FOR независимы друг от друга, и u не определяет автоматически документ для оператора UPDATE. Таким образом, следующий запрос является некорректным:
1 2 | |
UPDATE <keyExpression> WITH <document> IN <collection>¶
При использовании второго синтаксиса документ для обновления определяется keyExpression. Это может быть либо строка с ключом документа, либо объект, содержащий атрибут _key с ключом документа, либо выражение, которое оценивается как одно из этих двух. Существующий документ с этим ключом обновляется атрибутами, предоставленными объектом document (за исключением системных атрибутов _id, _key и _rev).
Следующий запрос добавляет или обновляет атрибут name документа, идентифицированного ключом my_key в коллекции users. Ключ передается в виде строки в keyExpression. Атрибуты для добавления или обновления передаются отдельно как объект document:
1 | |
Объект document может содержать атрибут _key, но он игнорируется.
Вы не можете определить документ для обновления с помощью атрибута _id или передать идентификатор документа в виде строки (например, "users/john"). Однако вы можете использовать PARSE_IDENTIFIER(<id>).key в качестве keyExpression для получения ключа документа в виде строки:
1 2 | |
Сравнение синтаксисов¶
Оба синтаксиса операции UPDATE позволяют вам определить документ для изменения и атрибуты для добавления или обновления. Документ для обновления эффективно идентифицируется ключом документа в сочетании с указанной коллекцией.
Операция UPDATE поддерживает различные способы указания ключа документа. Вы можете выбрать наиболее удобный для вас вариант синтаксиса.
Следующие запросы эквивалентны:
1 2 | |
1 2 | |
1 2 | |
1 2 | |
Выражения динамических ключей¶
Операция UPDATE может обновлять произвольные документы, используя любой из двух синтаксисов:
1 2 | |
1 2 | |
Нацелить на другую коллекцию¶
Документы, которые изменяет операция UPDATE, могут находиться в другой коллекции, чем те, которые были созданы предыдущей операцией FOR:
1 2 3 | |
Обратите внимание, как документы считываются из коллекции users, но обновляются в другой коллекции backup. Чтобы это работало, обе коллекции должны использовать совпадающие ключи документов.
Хотя переменная u содержит целый документ, она используется только для определения целевого документа. Атрибут _key объекта извлекается, и целевой документ определяется только значением строки ключа документа и указанной коллекцией операции UPDATE (backup). Ссылка на исходную коллекцию (users) отсутствует.
Использование текущего значения атрибута документа¶
Псевдопеременная OLD не поддерживается в выражениях WITH (она доступна после UPDATE). Чтобы получить доступ к текущему значению атрибута, обычно можно обратиться к документу через переменную цикла FOR, который используется для итерации по коллекции:
1 2 3 4 | |
Если цикла нет, потому что обновляется только один документ, то может не быть переменной, как указано выше (doc), которая позволит вам ссылаться на обновляемый документ:
1 | |
Чтобы получить доступ к текущему значению в этой ситуации, необходимо сначала получить документ и сохранить его в переменной:
1 2 3 4 | |
Таким образом можно изменить существующий атрибут на основе его текущего значения, например, увеличить счетчик:
1 2 3 | |
Если атрибут karma еще не существует, doc.karma оценивается в null. Выражение null + 1 приводит к тому, что новый атрибут karma устанавливается в 1. Если атрибут уже существует, то он увеличивается на 1.
Массивы также могут быть изменены:
1 2 3 | |
Если атрибут hobbies еще не существует, его удобно инициализировать как ["swimming" ] и в противном случае расширить.
Параметры запроса¶
Вы можете опционально установить параметры запроса для операции UPDATE:
1 | |
ignoreErrors¶
Вы можете использовать ignoreErrors для подавления ошибок запроса, которые могут возникнуть при попытке обновления несуществующих документов или при нарушении ограничений уникального ключа:
1 2 3 4 | |
Вы не можете изменять системные атрибуты _id, _key и _rev, но попытки изменить их игнорируются и не считаются ошибками.
keepNull¶
При обновлении атрибута до значения null, ArangoDB не удаляет атрибут из документа, а сохраняет это значение null. Чтобы удалить атрибуты в операции обновления, задайте им значение null и установите опцию keepNull в false. При этом удаляются указанные вами атрибуты, но не все ранее сохраненные атрибуты со значением null:
1 2 3 | |
Приведенный выше запрос удаляет атрибут notNeeded из документов и нормально обновляет атрибут foobar.
mergeObjects¶
Опция mergeObjects управляет тем, объединяется ли содержимое объекта, если атрибут объекта присутствует как в запросе UPDATE, так и в обновляемом документе.
Следующий запрос устанавливает атрибут name обновленного документа в то же значение, которое указано в запросе. Это происходит из-за того, что опция mergeObjects установлена в false:
1 2 3 4 5 | |
Напротив, следующий запрос объединяет содержимое атрибута name в исходном документе со значением, указанным в запросе:
1 2 3 4 5 | |
Атрибуты в name, которые присутствуют в обновляемом документе, но не в запросе, сохраняются. Атрибуты, присутствующие в обоих документах, перезаписываются значениями, указанными в запросе.
Примечание: значение по умолчанию для mergeObjects равно true, поэтому нет необходимости указывать его явно.
waitForSync¶
Для обеспечения долговечности данных при выполнении запроса на обновление существует опция запроса waitForSync:
1 2 3 | |
ignoreRevs¶
Чтобы случайно не перезаписать документы, которые были изменены с момента последнего извлечения, вы можете использовать опцию ignoreRevs, чтобы либо позволить ArangoDB сравнивать значение _rev и добиваться успеха, только если они совпадают, либо позволить ArangoDB игнорировать их (по умолчанию):
1 2 3 4 | |
exclusive¶
Движок RocksDB не требует блокировок на уровне коллекции. Различные операции записи в одну и ту же коллекцию не блокируют друг друга, если нет конфликтов запись-запись на одних и тех же документах. С точки зрения разработки приложений может быть желательным иметь исключительный доступ на запись в коллекции, чтобы упростить разработку. Обратите внимание, что записи не блокируют чтения в RocksDB. Исключительный доступ также может ускорить запросы на модификацию, поскольку мы избегаем проверки конфликтов.
Используйте опцию exclusive для достижения этого эффекта на основе каждого запроса:
1 2 3 4 | |
refillIndexCaches¶
Нужно ли обновлять существующие записи в кэше границ в памяти при обновлении документов границ.
1 2 | |
Возвращение измененных документов¶
При желании можно вернуть документы, измененные запросом. В этом случае за операцией UPDATE должна следовать операция RETURN. Допускаются также промежуточные операции LET. Эти операции могут ссылаться на псевдопеременные OLD и NEW. Псевдопеременная OLD ссылается на ревизии документа до обновления, а NEW - на ревизии документа после обновления.
И OLD, и NEW содержат все атрибуты документа, даже те, которые не указаны в выражении обновления.
1 2 3 4 | |
Ниже приведен пример использования переменной с именем previous для получения исходных документов до их модификации. Для каждого измененного документа возвращается ключ документа.
1 2 3 4 | |
Следующий запрос использует псевдо-значение NEW, чтобы вернуть обновленные документы без некоторых системных атрибутов:
1 2 3 4 | |
Также можно вернуть и OLD, и NEW:
1 2 3 | |
Транзакционность¶
На одном сервере обновления выполняются транзакционно по принципу "все или ничего".
Если используется движок RocksDB и включены промежуточные фиксации, запрос может выполнять промежуточные фиксации транзакций в случае, если запущенная транзакция (AQL-запрос) достигает заданных пороговых значений размера. В этом случае операции запроса, выполненные до этого момента, фиксируются и не откатываются в случае последующего отмены/отката. Это поведение можно контролировать, изменяя настройки промежуточной фиксации для движка RocksDB.
Для коллекций с шардированием вся операция запроса и/или обновления может не быть транзакционной, особенно если она затрагивает разные шарды и/или DB-серверы.