1
0
Fork 0
arangodb/Documentation/Books/Users/AqlOperations/Update.mdpp

178 lines
6.1 KiB
Plaintext

!CHAPTER UPDATE
The *UPDATE* keyword can be used to partially update documents in a collection. On a
single server, updates are executed transactionally in an all-or-nothing fashion.
For sharded collections, the entire update operation is not transactional.
Each *UPDATE* operation is restricted to a single collection, and the
[collection name](../Glossary/README.md#collection-name) must not be dynamic.
Only a single *UPDATE* statement per collection is allowed per AQL query, and
it cannot be followed by read operations that access the same collection, by
traversal operations, or AQL functions that can read documents.
The system attributes of documents (*_key*, *_id*, *_from*, *_to*, *_rev*) cannot be
updated.
The two syntaxes for an update operation are:
```
UPDATE document IN collection options
UPDATE key-expression WITH document IN collection options
```
*collection* must contain the name of the collection in which the documents should
be updated. *document* must be a document that contains the attributes and values
to be updated. When using the first syntax, *document* must also contain the *_key*
attribute to identify the document to be updated.
```
FOR u IN users
UPDATE { _key: u._key, name: CONCAT(u.firstName, u.lastName) } IN users
```
The following query is invalid because it does not contain a *_key* attribute and
thus it is not possible to determine the documents to be updated:
```
FOR u IN users
UPDATE { name: CONCAT(u.firstName, u.lastName) } IN users
```
When using the second syntax, *key-expression* provides the document identification.
This can either be a string (which must then contain the document key) or a
document, which must contain a *_key* attribute.
The following queries are equivalent:
```
FOR u IN users
UPDATE u._key WITH { name: CONCAT(u.firstName, u.lastName) } IN users
FOR u IN users
UPDATE { _key: u._key } WITH { name: CONCAT(u.firstName, u.lastName) } IN users
FOR u IN users
UPDATE u WITH { name: CONCAT(u.firstName, u.lastName) } IN users
```
An update operation may update arbitrary documents which do not need to be identical
to the ones produced by a preceding *FOR* statement:
```
FOR i IN 1..1000
UPDATE CONCAT('test', i) WITH { foobar: true } IN users
FOR u IN users
FILTER u.active == false
UPDATE u WITH { status: 'inactive' } IN backup
```
!SUBSECTION Setting query options
*options* can be used to suppress query errors that may occur when trying to
update non-existing documents or violating unique key constraints:
```
FOR i IN 1..1000
UPDATE { _key: CONCAT('test', i) } WITH { foobar: true } IN users OPTIONS { ignoreErrors: true }
```
An update operation will only update the attributes specified in *document* and
leave other attributes untouched. Internal attributes (such as *_id*, *_key*, *_rev*,
*_from* and *_to*) cannot be updated and are ignored when specified in *document*.
Updating a document will modify the document's revision number with a server-generated value.
When updating an attribute with a null value, ArangoDB will not remove the attribute
from the document but store a null value for it. To get rid of attributes in an update
operation, set them to null and provide the *keepNull* option:
```
FOR u IN users
UPDATE u WITH { foobar: true, notNeeded: null } IN users OPTIONS { keepNull: false }
```
The above query will remove the *notNeeded* attribute from the documents and update
the *foobar* attribute normally.
There is also the option *mergeObjects* that controls whether object contents will be
merged if an object attribute is present in both the *UPDATE* query and in the
to-be-updated document.
The following query will set the updated document's *name* attribute to the exact
same value that is specified in the query. This is due to the *mergeObjects* option
being set to *false*:
```
FOR u IN users
UPDATE u WITH { name: { first: "foo", middle: "b.", last: "baz" } } IN users OPTIONS { mergeObjects: false }
```
Contrary, the following query will merge the contents of the *name* attribute in the
original document with the value specified in the query:
```
FOR u IN users
UPDATE u WITH { name: { first: "foo", middle: "b.", last: "baz" } } IN users OPTIONS { mergeObjects: true }
```
Attributes in *name* that are present in the to-be-updated document but not in the
query will now be preserved. Attributes that are present in both will be overwritten
with the values specified in the query.
Note: the default value for *mergeObjects* is *true*, so there is no need to specify it
explicitly.
To make sure data are durable when an update query returns, there is the *waitForSync*
query option:
```
FOR u IN users
UPDATE u WITH { foobar: true } IN users OPTIONS { waitForSync: true }
```
!SUBSECTION Returning the modified documents
The modified documents can also be returned by the query. In this case, the `UPDATE`
statement needs to be followed a `RETURN` statement (intermediate `LET` statements
are allowed, too). These statements can refer to the pseudo-values `OLD` and `NEW`.
The `OLD` pseudo-value refers to the document revisions before the update, and `NEW`
refers to document revisions after the update.
Both `OLD` and `NEW` will contain all document attributes, even those not specified
in the update expression.
```
UPDATE document IN collection options RETURN OLD
UPDATE document IN collection options RETURN NEW
UPDATE key-expression WITH document IN collection options RETURN OLD
UPDATE key-expression WITH document IN collection options RETURN NEW
```
Following is an example using a variable named `previous` to capture the original
documents before modification. For each modified document, the document key is returned.
```
FOR u IN users
UPDATE u WITH { value: "test" }
LET previous = OLD
RETURN previous._key
```
The following query uses the `NEW` pseudo-value to return the updated documents,
without some of the system attributes:
```
FOR u IN users
UPDATE u WITH { value: "test" }
LET updated = NEW
RETURN UNSET(updated, "_key", "_id", "_rev")
```
It is also possible to return both `OLD` and `NEW`:
```
FOR u IN users
UPDATE u WITH { value: "test" }
RETURN { before: OLD, after: NEW }
```