1
0
Fork 0

Docs: Access current/OLD value in UPDATE

This commit is contained in:
Simran Brucherseifer 2016-08-22 18:34:26 +02:00
parent a542735683
commit 1e6503d1e0
1 changed files with 91 additions and 23 deletions

View File

@ -23,17 +23,17 @@ be updated. *document* must be a document that contains the attributes and value
to be updated. When using the first syntax, *document* must also contain the *_key* to be updated. When using the first syntax, *document* must also contain the *_key*
attribute to identify the document to be updated. attribute to identify the document to be updated.
``` ```js
FOR u IN users FOR u IN users
UPDATE { _key: u._key, name: CONCAT(u.firstName, u.lastName) } 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 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: thus it is not possible to determine the documents to be updated:
``` ```js
FOR u IN users FOR u IN users
UPDATE { name: CONCAT(u.firstName, u.lastName) } IN users UPDATE { name: CONCAT(u.firstName, " ", u.lastName) } IN users
``` ```
When using the second syntax, *keyExpression* provides the document identification. When using the second syntax, *keyExpression* provides the document identification.
@ -42,21 +42,21 @@ document, which must contain a *_key* attribute.
The following queries are equivalent: The following queries are equivalent:
``` ```js
FOR u IN users FOR u IN users
UPDATE u._key WITH { name: CONCAT(u.firstName, u.lastName) } IN users UPDATE u._key WITH { name: CONCAT(u.firstName, " ", u.lastName) } IN users
FOR u IN users FOR u IN users
UPDATE { _key: u._key } WITH { name: CONCAT(u.firstName, u.lastName) } IN users UPDATE { _key: u._key } WITH { name: CONCAT(u.firstName, " ", u.lastName) } IN users
FOR u IN users FOR u IN users
UPDATE u WITH { name: CONCAT(u.firstName, u.lastName) } 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 An update operation may update arbitrary documents which do not need to be identical
to the ones produced by a preceding *FOR* statement: to the ones produced by a preceding *FOR* statement:
``` ```js
FOR i IN 1..1000 FOR i IN 1..1000
UPDATE CONCAT('test', i) WITH { foobar: true } IN users UPDATE CONCAT('test', i) WITH { foobar: true } IN users
@ -65,14 +65,74 @@ FOR u IN users
UPDATE u WITH { status: 'inactive' } IN backup UPDATE u WITH { status: 'inactive' } IN backup
``` ```
!SUBSECTION Using the current value of a document attribute
The pseudo-variable `OLD` is not supported inside of `WITH` clauses (it is
available after `UPDATE`). To access the current attribute value, you can
usually refer to a document via the variable of the `FOR` loop, which is used
to iterate over a collection:
```js
FOR doc IN users
UPDATE doc WITH {
fullName: CONCAT(doc.firstName, " ", doc.lastName)
} IN users
```
If there is no loop, because a single document is updated only, then there
might not be a variable like above (`doc`), which would let you refer to the
document which is being updated:
```js
UPDATE "users/john" WITH { ... } IN users
```
To access the current value in this situation, the document has to be retrieved
and stored in a variable first:
```js
LET doc = DOCUMENT("users/john")
UPDATE doc WITH {
fullName: CONCAT(doc.firstName, " ", doc.lastName)
} IN users
```
An existing attribute can be modified based on its current value this way,
to increment a counter for instance:
```js
UPDATE doc WITH {
karma: doc.karma + 1
} IN users
```
If the attribute `karma` doesn't exist yet, `doc.karma` is evaluated to *null*.
The expression `null + 1` results in the new attribute `karma` being set to *1*.
If the attribute does exist, then it is increased by *1*.
Arrays can be mutated too of course:
```js
UPDATE doc WITH {
hobbies: PUSH(doc.hobbies, "swimming")
} IN users
```
If the attribute `hobbies` doesn't exist yet, it is conveniently initialized
as `[ "swimming" ]` and otherwise extended.
!SUBSECTION Setting query options !SUBSECTION Setting query options
*options* can be used to suppress query errors that may occur when trying to *options* can be used to suppress query errors that may occur when trying to
update non-existing documents or violating unique key constraints: update non-existing documents or violating unique key constraints:
``` ```js
FOR i IN 1..1000 FOR i IN 1..1000
UPDATE { _key: CONCAT('test', i) } WITH { foobar: true } IN users OPTIONS { ignoreErrors: true } 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 An update operation will only update the attributes specified in *document* and
@ -84,9 +144,12 @@ When updating an attribute with a null value, ArangoDB will not remove the attri
from the document but store a null value for it. To get rid of attributes in an update 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: operation, set them to null and provide the *keepNull* option:
``` ```js
FOR u IN users FOR u IN users
UPDATE u WITH { foobar: true, notNeeded: null } IN users OPTIONS { keepNull: false } 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 above query will remove the *notNeeded* attribute from the documents and update
@ -100,17 +163,21 @@ The following query will set the updated document's *name* attribute to the exac
same value that is specified in the query. This is due to the *mergeObjects* option same value that is specified in the query. This is due to the *mergeObjects* option
being set to *false*: being set to *false*:
``` ```js
FOR u IN users FOR u IN users
UPDATE u WITH { name: { first: "foo", middle: "b.", last: "baz" } } IN users OPTIONS { mergeObjects: false } 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 Contrary, the following query will merge the contents of the *name* attribute in the
original document with the value specified in the query: original document with the value specified in the query:
``` ```js
FOR u IN users FOR u IN users
UPDATE u WITH { name: { first: "foo", middle: "b.", last: "baz" } } IN users OPTIONS { mergeObjects: true } 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 Attributes in *name* that are present in the to-be-updated document but not in the
@ -123,9 +190,11 @@ explicitly.
To make sure data are durable when an update query returns, there is the *waitForSync* To make sure data are durable when an update query returns, there is the *waitForSync*
query option: query option:
``` ```js
FOR u IN users FOR u IN users
UPDATE u WITH { foobar: true } IN users OPTIONS { waitForSync: true } UPDATE u WITH {
foobar: true
} IN users OPTIONS { waitForSync: true }
``` ```
!SUBSECTION Returning the modified documents !SUBSECTION Returning the modified documents
@ -149,7 +218,7 @@ UPDATE keyExpression WITH document IN collection options RETURN NEW
Following is an example using a variable named `previous` to capture the original 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. documents before modification. For each modified document, the document key is returned.
``` ```js
FOR u IN users FOR u IN users
UPDATE u WITH { value: "test" } UPDATE u WITH { value: "test" }
LET previous = OLD LET previous = OLD
@ -159,7 +228,7 @@ FOR u IN users
The following query uses the `NEW` pseudo-value to return the updated documents, The following query uses the `NEW` pseudo-value to return the updated documents,
without some of the system attributes: without some of the system attributes:
``` ```js
FOR u IN users FOR u IN users
UPDATE u WITH { value: "test" } UPDATE u WITH { value: "test" }
LET updated = NEW LET updated = NEW
@ -168,9 +237,8 @@ FOR u IN users
It is also possible to return both `OLD` and `NEW`: It is also possible to return both `OLD` and `NEW`:
``` ```js
FOR u IN users FOR u IN users
UPDATE u WITH { value: "test" } UPDATE u WITH { value: "test" }
RETURN { before: OLD, after: NEW } RETURN { before: OLD, after: NEW }
``` ```