From 1e6503d1e048461b548e18c0869fa49b7793a855 Mon Sep 17 00:00:00 2001 From: Simran Brucherseifer Date: Mon, 22 Aug 2016 18:34:26 +0200 Subject: [PATCH] Docs: Access current/OLD value in UPDATE --- .../Books/AQL/Operations/Update.mdpp | 114 ++++++++++++++---- 1 file changed, 91 insertions(+), 23 deletions(-) diff --git a/Documentation/Books/AQL/Operations/Update.mdpp b/Documentation/Books/AQL/Operations/Update.mdpp index 3dbdce78e4..ee3205da15 100644 --- a/Documentation/Books/AQL/Operations/Update.mdpp +++ b/Documentation/Books/AQL/Operations/Update.mdpp @@ -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* attribute to identify the document to be updated. -``` +```js 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 thus it is not possible to determine the documents to be updated: -``` +```js 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. @@ -42,21 +42,21 @@ document, which must contain a *_key* attribute. The following queries are equivalent: -``` +```js 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 - 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 - 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 to the ones produced by a preceding *FOR* statement: -``` +```js FOR i IN 1..1000 UPDATE CONCAT('test', i) WITH { foobar: true } IN users @@ -65,14 +65,74 @@ FOR u IN users 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 *options* can be used to suppress query errors that may occur when trying to update non-existing documents or violating unique key constraints: -``` +```js 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 @@ -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 operation, set them to null and provide the *keepNull* option: -``` +```js 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 @@ -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 being set to *false*: -``` +```js 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 original document with the value specified in the query: -``` +```js 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 @@ -123,9 +190,11 @@ explicitly. To make sure data are durable when an update query returns, there is the *waitForSync* query option: -``` +```js 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 @@ -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 documents before modification. For each modified document, the document key is returned. -``` +```js FOR u IN users UPDATE u WITH { value: "test" } LET previous = OLD @@ -159,7 +228,7 @@ FOR u IN users The following query uses the `NEW` pseudo-value to return the updated documents, without some of the system attributes: -``` +```js FOR u IN users UPDATE u WITH { value: "test" } LET updated = NEW @@ -168,9 +237,8 @@ FOR u IN users It is also possible to return both `OLD` and `NEW`: -``` +```js FOR u IN users UPDATE u WITH { value: "test" } RETURN { before: OLD, after: NEW } ``` -