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-серверы.