From e8d9eb975cb2a7458328b3104b754bdab783e09e Mon Sep 17 00:00:00 2001 From: Paula Date: Mon, 5 Feb 2024 16:55:08 +1100 Subject: [PATCH 1/3] versioning support for document operations --- .../3.12/aql/high-level-operations/replace.md | 12 ++++ .../3.12/aql/high-level-operations/update.md | 12 ++++ .../@arangodb/collection-object.md | 34 +++++++++ .../version-3.12/api-changes-in-3-12.md | 18 +++++ .../version-3.12/whats-new-in-3-12.md | 72 +++++++++++++++++++ 5 files changed, 148 insertions(+) diff --git a/site/content/3.12/aql/high-level-operations/replace.md b/site/content/3.12/aql/high-level-operations/replace.md index bc96d97736..f16e875580 100644 --- a/site/content/3.12/aql/high-level-operations/replace.md +++ b/site/content/3.12/aql/high-level-operations/replace.md @@ -252,6 +252,18 @@ REPLACE { _key: "123", _from: "vert/C", _to: "vert/D" } IN edgeColl OPTIONS { refillIndexCaches: true } ``` +### `versionAttribute` + +The optional `versionAttribute` can be used for external versioning +support. If set, the attribute with the name specified by the option is +looked up in the document to be replaced and its content is read and compared numerically to the value of +the versioning attribute in the document that replaces it. +If the version number in the new document is higher than in the document that +already exists in the database, then the operation is performed normally. +If the version number in the new document is lower or equal to what exists in +the database, the operation is not performed and behaves like a no-op. No error +is returned in this case. + ## Returning the modified documents You can optionally return the documents modified by the query. In this case, the `REPLACE` diff --git a/site/content/3.12/aql/high-level-operations/update.md b/site/content/3.12/aql/high-level-operations/update.md index 1152ebc56c..850deb62e8 100644 --- a/site/content/3.12/aql/high-level-operations/update.md +++ b/site/content/3.12/aql/high-level-operations/update.md @@ -368,6 +368,18 @@ UPDATE { _key: "123", _from: "vert/C", _to: "vert/D" } IN edgeColl OPTIONS { refillIndexCaches: true } ``` +### `versionAttribute` + +The optional `versionAttribute` can be used for external versioning +support. If set, the attribute with the name specified by the option is +looked up in the document to be updated and its content is read and compared numerically to the value of +the versioning attribute in the document that updates it. +If the version number in the new document is higher than in the document that +already exists in the database, then the operation is performed normally. +If the version number in the new document is lower or equal to what exists in +the database, the operation is not performed and behaves like a no-op. No error +is returned in this case. + ## Returning the modified documents You can optionally return the documents modified by the query. In this case, the `UPDATE` diff --git a/site/content/3.12/develop/javascript-api/@arangodb/collection-object.md b/site/content/3.12/develop/javascript-api/@arangodb/collection-object.md index 523dfd866b..9bd0a477ef 100644 --- a/site/content/3.12/develop/javascript-api/@arangodb/collection-object.md +++ b/site/content/3.12/develop/javascript-api/@arangodb/collection-object.md @@ -996,6 +996,18 @@ used to specify the following options: existing document's value. If set to `true`, objects will be merged. The default is `true`. This option controls the update-insert behavior only. +- `versionAttribute`: The optional `versionAttribute` adds external versioning + support and can be used with `overwriteMode: "update"` or `overwriteMode: "replace"`. + If set, the attribute with the name specified by the property is + looked up in the document to be updated or to be replaced. + If no such attribute exists, the operation is performed as usual. If such an + attribute exists, its content is read and compared numerically to the value of + the versioning attribute in the document that updates or replaces it. + If the version number in the new document is higher than in the document that + already exists in the database, then the operation is performed normally. + If the version number in the new document is lower or equal to what exists in + the database, the operation is not performed and behaves like a no-op. No error + is returned in this case. --- @@ -1301,6 +1313,17 @@ Replaces an existing document, with additional options passed as an object: revision of the document is returned in the output under the attribute `old`. - `silent`: If this flag is set to `true`, no output is returned. +- `versionAttribute`: The optional `versionAttribute` adds external versioning + support. If set, the attribute with the name specified by the property is + looked up in the document to be replaced. + If no such attribute exists, the operation is performed as usual. If such an + attribute exists, its content is read and compared numerically to the value of + the versioning attribute in the document that replaces it. + If the version number in the new document is higher than in the document that + already exists in the database, then the operation is performed normally. + If the version number in the new document is lower or equal to what exists in + the database, the operation is not performed and behaves like a no-op. No error + is returned in this case. --- @@ -1473,6 +1496,17 @@ an object: set to `false`, the value in the patch document will overwrite the existing document's value. If set to `true`, objects will be merged. The default is `true`. +- `versionAttribute`: The optional `versionAttribute` adds external versioning + support. If set, the attribute with the name specified by the property is + looked up in the document to be updated. + If no such attribute exists, the operation is performed as usual. If such an + attribute exists, its content is read and compared numerically to the value of + the versioning attribute in the document that updates it. + If the version number in the new document is higher than in the document that + already exists in the database, then the operation is performed normally. + If the version number in the new document is lower or equal to what exists in + the database, the operation is not performed and behaves like a no-op. No error + is returned in this case. --- diff --git a/site/content/3.12/release-notes/version-3.12/api-changes-in-3-12.md b/site/content/3.12/release-notes/version-3.12/api-changes-in-3-12.md index c2d492519a..6ce4993d9e 100644 --- a/site/content/3.12/release-notes/version-3.12/api-changes-in-3-12.md +++ b/site/content/3.12/release-notes/version-3.12/api-changes-in-3-12.md @@ -387,3 +387,21 @@ not handle larger amounts of data and were thus very limited. Users of the JavaScript-based traversal API should use [AQL traversal queries](../../aql/graphs/traversals.md) instead. + +### `collection` object + +`collection.replace(object, data, options)` and +`collection.update(object, data, options)` now have an optional +`versionAttribute` property that adds external versioning support. It can also +be used for `collection.insert(data, options)` with `overwriteMode: "update"` +or `overwriteMode: "replace"`. + +If set, the attribute with the name specified by the property is looked up in +the document to be replaced or updated and its content is read and compared +numerically to the value of the versioning attribute in the document that +updates or replaces it. +If the version number in the new document is higher than in the document that +already exists in the database, then the operation is performed normally. +If the version number in the new document is lower or equal to what exists in +the database, the operation is not performed and behaves like a no-op. No error +is returned in this case. \ No newline at end of file diff --git a/site/content/3.12/release-notes/version-3.12/whats-new-in-3-12.md b/site/content/3.12/release-notes/version-3.12/whats-new-in-3-12.md index 0b48b15668..4470d63f51 100644 --- a/site/content/3.12/release-notes/version-3.12/whats-new-in-3-12.md +++ b/site/content/3.12/release-notes/version-3.12/whats-new-in-3-12.md @@ -341,6 +341,78 @@ The `move-filters-into-enumerate` optimizer rule can now also move filters into performance of queries that do a lot of filtering on longer lists of non-collection data. +### `versionAttribute` property for `UPDATE` and `REPLACE` operations + +`UPDATE` and `REPLACE` operations now support an optional `versionAttribute` +property. If set, the attribute with the name specified by the property is +looked up in the document to be updated or to be replaced. + +This simple versioning can help to avoid overwriting existing data with older +versions in case data is transferred from an external system into ArangoDB +and the copies are currently not in sync. + +The `versionAttribute` property can be used for `INSERT` operations with +`overwriteMode: "update"` or `overwriteMode: "replace"`. +It can also be used inside AQL queries by specifying it in the `OPTIONS` +clause of an `UPDATE`, `REPLACE`, and `INSERT` operation. + +If no such attribute exists, the operation is performed as usual. If such an +attribute exists, its content is read and compared numerically to the value of +the versioning attribute in the document that updates or replaces it. +If the version number in the new document is higher than in the document that +already exists in the database, then the operation is performed normally. +If the version number in the new document is lower or equal to what exists in +the database, the operation is not performed and behaves like a no-op. No error +is returned in this case. + +**Examples:** + +Inserts the new document normally: +```js +db.collection.insert({_key: "hello", value: 1, ver: 1}); +``` + +Updates the document because the value of the `versionAttribute` is higher in the +new document: +```js +db.collection.update("hello", + {value: 2, ver: 2}, + {versionAttribute: "ver"}); +``` + +Does not update the document because the value of the `versionAttribute` is lower +in the new document: +```js +db.collection.update("hello", + {value: 3, ver: 1}, + {versionAttribute: "ver"}); +``` + +Updates the document because the key already exists and the value of the +`versionAttribute` is higher in the new document: +```js +db.collection.insert({_key: "hello", value: 4, ver: 3}, + {overwriteMode: "update", versionAttribute: "ver"}); +``` + +```js +db._query("UPDATE 'hello' WITH {value: 5, ver: 4} IN collection + OPTIONS {versionAttribute: 'ver'}"); +``` + +Versioning is opt-in and no version checking is performed for +operations for which the `versionAttribute` property was not set as part of +the `UPDATE` and `REPLACE` operations or as an option in the AQL query. Document +removal operations do not support versioning. Removal operations are always +carried out normally without checking the version attribute, even if it is specified. + +Note that version checking is performed only if both the existing version of +the document in the database and the new document version contain the version +attribute with numeric values between `0` and `18446744073709551615`. +If neither the existing document in the database nor the new document version +does not contain the version attribute, or if the version attribute in any of +the two is not a number inside the valid range, the `UPDATE` and `REPLACE` operations behave as if no version checking was requested. + ## Indexing ### Stored values can contain the `_id` attribute From be7aa59b9bc182b0c845e525a0d08c62b2015dfa Mon Sep 17 00:00:00 2001 From: Paula Date: Tue, 20 Feb 2024 15:23:49 +1100 Subject: [PATCH 2/3] add http api changes --- site/content/3.12/develop/http-api/documents.md | 16 ++++++++++++++++ .../version-3.12/api-changes-in-3-12.md | 10 ++++++++++ 2 files changed, 26 insertions(+) diff --git a/site/content/3.12/develop/http-api/documents.md b/site/content/3.12/develop/http-api/documents.md index 41a3036f20..6c190c9108 100644 --- a/site/content/3.12/develop/http-api/documents.md +++ b/site/content/3.12/develop/http-api/documents.md @@ -856,6 +856,14 @@ paths: replacements affect the edge index or cache-enabled persistent indexes. schema: type: boolean + - name: versionAttribute + in: query + required: false + description: | + Adds external versioning support. If set, the attribute with the name + specified by the property is looked up in the document to be replaced. + schema: + type: string - name: If-Match in: header required: false @@ -1178,6 +1186,14 @@ paths: affect the edge index or cache-enabled persistent indexes. schema: type: boolean + - name: versionAttribute + in: query + required: false + description: | + Adds external versioning support. If set, the attribute with the name + specified by the property is looked up in the document to be updated. + schema: + type: string - name: If-Match in: header required: false diff --git a/site/content/3.12/release-notes/version-3.12/api-changes-in-3-12.md b/site/content/3.12/release-notes/version-3.12/api-changes-in-3-12.md index 70ec773bc1..41079b5c54 100644 --- a/site/content/3.12/release-notes/version-3.12/api-changes-in-3-12.md +++ b/site/content/3.12/release-notes/version-3.12/api-changes-in-3-12.md @@ -239,6 +239,16 @@ and defaults to `[]`. See the [`optimizeTopK` View property](../../index-and-search/arangosearch/arangosearch-views-reference.md#view-properties) for details. +#### Document API + +The `PUT /_api/document/{collection}/{key}` and `PATCH /_api/document/{collection}/{key}` +endpoints accept a new `versionAttribute` property that adds external versioning +support. +If set, the attribute with the name specified by the property is looked up in +the document to be replaced or updated and its content is read and compared +numerically to the value of the versioning attribute in the document that +updates or replaces it. + #### Index API ##### `optimizeTopK` for inverted indexes From 0a3e88fcbc360127366c9d2b2e8c8cd2e1fcfd15 Mon Sep 17 00:00:00 2001 From: Simran Spiller Date: Wed, 21 Feb 2024 16:57:52 +0100 Subject: [PATCH 3/3] Review --- .../features/highlights-by-version.md | 4 + .../3.12/aql/high-level-operations/insert.md | 33 ++++ .../3.12/aql/high-level-operations/replace.md | 34 +++- .../3.12/aql/high-level-operations/update.md | 34 +++- .../3.12/develop/http-api/documents.md | 148 ++++++++++++++++- .../@arangodb/collection-object.md | 89 +++++++---- .../version-3.12/api-changes-in-3-12.md | 50 +++--- .../version-3.12/whats-new-in-3-12.md | 149 +++++++++--------- 8 files changed, 396 insertions(+), 145 deletions(-) diff --git a/site/content/3.12/about-arangodb/features/highlights-by-version.md b/site/content/3.12/about-arangodb/features/highlights-by-version.md index b2e84b0743..e496bfc8ba 100644 --- a/site/content/3.12/about-arangodb/features/highlights-by-version.md +++ b/site/content/3.12/about-arangodb/features/highlights-by-version.md @@ -17,6 +17,10 @@ aliases: Accelerate wildcard searches against Views and inverted indexes with _n_-grams to quickly find candidate matches. +- [**External versioning**](../../release-notes/version-3.12/whats-new-in-3-12.md#external-versioning-support): + Specify any top-level attribute to compare whether the version number is higher + than the currently stored one when updating or replacing documents. + **Enterprise Edition** - [**ArangoSearch WAND optimization**](../../index-and-search/arangosearch/performance.md#wand-optimization): diff --git a/site/content/3.12/aql/high-level-operations/insert.md b/site/content/3.12/aql/high-level-operations/insert.md index e39c6765fb..0d954b499c 100644 --- a/site/content/3.12/aql/high-level-operations/insert.md +++ b/site/content/3.12/aql/high-level-operations/insert.md @@ -175,6 +175,39 @@ INSERT { _from: "vert/A", _to: "vert/B" } INTO coll OPTIONS { refillIndexCaches: true } ``` +### `versionAttribute` + +Only applicable if `overwrite` is set to `true` or `overwriteMode` +is set to `update` or `replace`. + +You can use the `versionAttribute` option for external versioning support. +If set, the attribute with the name specified by the option is looked up in the +stored document and the attribute value is compared numerically to the value of +the versioning attribute in the supplied document that is supposed to update/replace it. + +If the version number in the new document is higher (rounded down to a whole number) +than in the document that already exists in the database, then the update/replace +operation is performed normally. This is also the case if the new versioning +attribute has a non-numeric value, if it is a negative number, or if the +attribute doesn't exist in the supplied or stored document. + +If the version number in the new document is lower or equal to what exists in +the database, the operation is not performed and the existing document thus not +changed. No error is returned in this case. + +The attribute can only be a top-level attribute. + +For example, the following query conditionally replaces an existing document with +the key `"123"` if the attribute `externalVersion` currently has a value below `5`: + +```aql +INSERT { _key: "123", externalVersion: 5, anotherAttribute: true } IN coll + OPTIONS { overwriteMode: "replace", versionAttribute: "externalVersion" } +``` + +You can check if `OLD._rev` (if not `null`) and `NEW._rev` are different to determine if the +document has been changed. + ## Returning the inserted documents The inserted documents can also be returned by the query. In this case, the `INSERT` diff --git a/site/content/3.12/aql/high-level-operations/replace.md b/site/content/3.12/aql/high-level-operations/replace.md index f16e875580..950bf27128 100644 --- a/site/content/3.12/aql/high-level-operations/replace.md +++ b/site/content/3.12/aql/high-level-operations/replace.md @@ -254,15 +254,33 @@ REPLACE { _key: "123", _from: "vert/C", _to: "vert/D" } IN edgeColl ### `versionAttribute` -The optional `versionAttribute` can be used for external versioning -support. If set, the attribute with the name specified by the option is -looked up in the document to be replaced and its content is read and compared numerically to the value of -the versioning attribute in the document that replaces it. -If the version number in the new document is higher than in the document that -already exists in the database, then the operation is performed normally. +You can use the `versionAttribute` option for external versioning support. +If set, the attribute with the name specified by the option is looked up in the +stored document and the attribute value is compared numerically to the value of +the versioning attribute in the supplied document that is supposed to replace it. + +If the version number in the new document is higher (rounded down to a whole number) +than in the document that already exists in the database, then the replace +operation is performed normally. This is also the case if the new versioning +attribute has a non-numeric value, if it is a negative number, or if the +attribute doesn't exist in the supplied or stored document. + If the version number in the new document is lower or equal to what exists in -the database, the operation is not performed and behaves like a no-op. No error -is returned in this case. +the database, the operation is not performed and the existing document thus not +changed. No error is returned in this case. + +The attribute can only be a top-level attribute. + +For example, the following query conditionally replaces an existing document with +the key `"123"` if the attribute `externalVersion` currently has a value below `5`: + +```aql +REPLACE { _key: "123", externalVersion: 5, anotherAttribute: true } IN coll + OPTIONS { versionAttribute: "externalVersion" } +``` + +You can check if `OLD._rev` and `NEW._rev` are different to determine if the +document has been changed. ## Returning the modified documents diff --git a/site/content/3.12/aql/high-level-operations/update.md b/site/content/3.12/aql/high-level-operations/update.md index 850deb62e8..6b56a6b2a0 100644 --- a/site/content/3.12/aql/high-level-operations/update.md +++ b/site/content/3.12/aql/high-level-operations/update.md @@ -370,15 +370,33 @@ UPDATE { _key: "123", _from: "vert/C", _to: "vert/D" } IN edgeColl ### `versionAttribute` -The optional `versionAttribute` can be used for external versioning -support. If set, the attribute with the name specified by the option is -looked up in the document to be updated and its content is read and compared numerically to the value of -the versioning attribute in the document that updates it. -If the version number in the new document is higher than in the document that -already exists in the database, then the operation is performed normally. +You can use the `versionAttribute` option for external versioning support. +If set, the attribute with the name specified by the option is looked up in the +stored document and the attribute value is compared numerically to the value of +the versioning attribute in the supplied document that is supposed to update it. + +If the version number in the new document is higher (rounded down to a whole number) +than in the document that already exists in the database, then the update +operation is performed normally. This is also the case if the new versioning +attribute has a non-numeric value, if it is a negative number, or if the +attribute doesn't exist in the supplied or stored document. + If the version number in the new document is lower or equal to what exists in -the database, the operation is not performed and behaves like a no-op. No error -is returned in this case. +the database, the operation is not performed and the existing document thus not +changed. No error is returned in this case. + +The attribute can only be a top-level attribute. + +For example, the following query conditionally updates an existing document with +the key `"123"` if the attribute `externalVersion` currently has a value below `5`: + +```aql +UPDATE { _key: "123", externalVersion: 5, anotherAttribute: true } IN coll + OPTIONS { versionAttribute: "externalVersion" } +``` + +You can check if `OLD._rev` and `NEW._rev` are different to determine if the +document has been changed. ## Returning the modified documents diff --git a/site/content/3.12/develop/http-api/documents.md b/site/content/3.12/develop/http-api/documents.md index 6c190c9108..f9c1488eef 100644 --- a/site/content/3.12/develop/http-api/documents.md +++ b/site/content/3.12/develop/http-api/documents.md @@ -476,6 +476,34 @@ paths: affect the edge index or cache-enabled persistent indexes. schema: type: boolean + - name: versionAttribute + in: query + required: false + description: | + Only applicable if `overwrite` is set to `true` or `overwriteMode` + is set to `update` or `replace`. + + You can use the `versionAttribute` option for external versioning support. + If set, the attribute with the name specified by the option is looked up in the + stored document and the attribute value is compared numerically to the value of + the versioning attribute in the supplied document that is supposed to update/replace it. + + If the version number in the new document is higher (rounded down to a whole number) + than in the document that already exists in the database, then the update/replace + operation is performed normally. This is also the case if the new versioning + attribute has a non-numeric value, if it is a negative number, or if the + attribute doesn't exist in the supplied or stored document. + + If the version number in the new document is lower or equal to what exists in + the database, the operation is not performed and the existing document thus not + changed. No error is returned in this case. + + The attribute can only be a top-level attribute. + + You can check if `_oldRev` (if present) and `_rev` are different to determine if the + document has been changed. + schema: + type: string - name: x-arango-trx-id in: header required: false @@ -860,8 +888,25 @@ paths: in: query required: false description: | - Adds external versioning support. If set, the attribute with the name - specified by the property is looked up in the document to be replaced. + You can use the `versionAttribute` option for external versioning support. + If set, the attribute with the name specified by the option is looked up in the + stored document and the attribute value is compared numerically to the value of + the versioning attribute in the supplied document that is supposed to replace it. + + If the version number in the new document is higher (rounded down to a whole number) + than in the document that already exists in the database, then the replace + operation is performed normally. This is also the case if the new versioning + attribute has a non-numeric value, if it is a negative number, or if the + attribute doesn't exist in the supplied or stored document. + + If the version number in the new document is lower or equal to what exists in + the database, the operation is not performed and the existing document thus not + changed. No error is returned in this case. + + The attribute can only be a top-level attribute. + + You can check if `_oldRev` and `_rev` are different to determine if the + document has been changed. schema: type: string - name: If-Match @@ -1190,8 +1235,25 @@ paths: in: query required: false description: | - Adds external versioning support. If set, the attribute with the name - specified by the property is looked up in the document to be updated. + You can use the `versionAttribute` option for external versioning support. + If set, the attribute with the name specified by the option is looked up in the + stored document and the attribute value is compared numerically to the value of + the versioning attribute in the supplied document that is supposed to update it. + + If the version number in the new document is higher (rounded down to a whole number) + than in the document that already exists in the database, then the update + operation is performed normally. This is also the case if the new versioning + attribute has a non-numeric value, if it is a negative number, or if the + attribute doesn't exist in the supplied or stored document. + + If the version number in the new document is lower or equal to what exists in + the database, the operation is not performed and the existing document thus not + changed. No error is returned in this case. + + The attribute can only be a top-level attribute. + + You can check if `_oldRev` and `_rev` are different to determine if the + document has been changed. schema: type: string - name: If-Match @@ -1891,6 +1953,34 @@ paths: affect the edge index or cache-enabled persistent indexes. schema: type: boolean + - name: versionAttribute + in: query + required: false + description: | + Only applicable if `overwrite` is set to `true` or `overwriteMode` + is set to `update` or `replace`. + + You can use the `versionAttribute` option for external versioning support. + If set, the attribute with the name specified by the option is looked up in the + stored document and the attribute value is compared numerically to the value of + the versioning attribute in the supplied document that is supposed to update/replace it. + + If the version number in the new document is higher (rounded down to a whole number) + than in the document that already exists in the database, then the update/replace + operation is performed normally. This is also the case if the new versioning + attribute has a non-numeric value, if it is a negative number, or if the + attribute doesn't exist in the supplied or stored document. + + If the version number in the new document is lower or equal to what exists in + the database, the operation is not performed and the existing document thus not + changed. No error is returned in this case. + + The attribute can only be a top-level attribute. + + You can check if `_oldRev` (if present) and `_rev` are different to determine if the + document has been changed. + schema: + type: string - name: x-arango-trx-id in: header required: false @@ -2162,6 +2252,31 @@ paths: replacements affect the edge index or cache-enabled persistent indexes. schema: type: boolean + - name: versionAttribute + in: query + required: false + description: | + You can use the `versionAttribute` option for external versioning support. + If set, the attribute with the name specified by the option is looked up in the + stored document and the attribute value is compared numerically to the value of + the versioning attribute in the supplied document that is supposed to replace it. + + If the version number in the new document is higher (rounded down to a whole number) + than in the document that already exists in the database, then the replace + operation is performed normally. This is also the case if the new versioning + attribute has a non-numeric value, if it is a negative number, or if the + attribute doesn't exist in the supplied or stored document. + + If the version number in the new document is lower or equal to what exists in + the database, the operation is not performed and the existing document thus not + changed. No error is returned in this case. + + The attribute can only be a top-level attribute. + + You can check if `_oldRev` and `_rev` are different to determine if the + document has been changed. + schema: + type: string - name: x-arango-trx-id in: header required: false @@ -2384,6 +2499,31 @@ paths: affect the edge index or cache-enabled persistent indexes. schema: type: boolean + - name: versionAttribute + in: query + required: false + description: | + You can use the `versionAttribute` option for external versioning support. + If set, the attribute with the name specified by the option is looked up in the + stored document and the attribute value is compared numerically to the value of + the versioning attribute in the supplied document that is supposed to update it. + + If the version number in the new document is higher (rounded down to a whole number) + than in the document that already exists in the database, then the update + operation is performed normally. This is also the case if the new versioning + attribute has a non-numeric value, if it is a negative number, or if the + attribute doesn't exist in the supplied or stored document. + + If the version number in the new document is lower or equal to what exists in + the database, the operation is not performed and the existing document thus not + changed. No error is returned in this case. + + The attribute can only be a top-level attribute. + + You can check if `_oldRev` and `_rev` are different to determine if the + document has been changed. + schema: + type: string - name: x-arango-trx-id in: header required: false diff --git a/site/content/3.12/develop/javascript-api/@arangodb/collection-object.md b/site/content/3.12/develop/javascript-api/@arangodb/collection-object.md index 9bd0a477ef..1c5b33d663 100644 --- a/site/content/3.12/develop/javascript-api/@arangodb/collection-object.md +++ b/site/content/3.12/develop/javascript-api/@arangodb/collection-object.md @@ -996,18 +996,28 @@ used to specify the following options: existing document's value. If set to `true`, objects will be merged. The default is `true`. This option controls the update-insert behavior only. -- `versionAttribute`: The optional `versionAttribute` adds external versioning - support and can be used with `overwriteMode: "update"` or `overwriteMode: "replace"`. - If set, the attribute with the name specified by the property is - looked up in the document to be updated or to be replaced. - If no such attribute exists, the operation is performed as usual. If such an - attribute exists, its content is read and compared numerically to the value of - the versioning attribute in the document that updates or replaces it. - If the version number in the new document is higher than in the document that - already exists in the database, then the operation is performed normally. +- `versionAttribute`: Only applicable if `overwrite` is set to `true` or + `overwriteMode` is set to `update` or `replace`. + + You can use the `versionAttribute` option for external versioning support. + If set, the attribute with the name specified by the option is looked up in the + stored document and the attribute value is compared numerically to the value of + the versioning attribute in the supplied document that is supposed to update/replace it. + + If the version number in the new document is higher (rounded down to a whole number) + than in the document that already exists in the database, then the update/replace + operation is performed normally. This is also the case if the new versioning + attribute has a non-numeric value, if it is a negative number, or if the + attribute doesn't exist in the supplied or stored document. + If the version number in the new document is lower or equal to what exists in - the database, the operation is not performed and behaves like a no-op. No error - is returned in this case. + the database, the operation is not performed and the existing document thus not + changed. No error is returned in this case. + + The attribute can only be a top-level attribute. + + You can check if `_oldRev` (if present) and `_rev` are different to determine if the + document has been changed. --- @@ -1313,18 +1323,26 @@ Replaces an existing document, with additional options passed as an object: revision of the document is returned in the output under the attribute `old`. - `silent`: If this flag is set to `true`, no output is returned. -- `versionAttribute`: The optional `versionAttribute` adds external versioning - support. If set, the attribute with the name specified by the property is - looked up in the document to be replaced. - If no such attribute exists, the operation is performed as usual. If such an - attribute exists, its content is read and compared numerically to the value of - the versioning attribute in the document that replaces it. - If the version number in the new document is higher than in the document that - already exists in the database, then the operation is performed normally. +- `versionAttribute`: + You can use the `versionAttribute` option for external versioning support. + If set, the attribute with the name specified by the option is looked up in the + stored document and the attribute value is compared numerically to the value of + the versioning attribute in the supplied document that is supposed to replace it. + + If the version number in the new document is higher (rounded down to a whole number) + than in the document that already exists in the database, then the replace + operation is performed normally. This is also the case if the new versioning + attribute has a non-numeric value, if it is a negative number, or if the + attribute doesn't exist in the supplied or stored document. + If the version number in the new document is lower or equal to what exists in - the database, the operation is not performed and behaves like a no-op. No error - is returned in this case. + the database, the operation is not performed and the existing document thus not + changed. No error is returned in this case. + + The attribute can only be a top-level attribute. + You can check if `_oldRev` and `_rev` are different to determine if the + document has been changed. --- `collection.replace(document-identifier, data [, options])` @@ -1496,17 +1514,26 @@ an object: set to `false`, the value in the patch document will overwrite the existing document's value. If set to `true`, objects will be merged. The default is `true`. -- `versionAttribute`: The optional `versionAttribute` adds external versioning - support. If set, the attribute with the name specified by the property is - looked up in the document to be updated. - If no such attribute exists, the operation is performed as usual. If such an - attribute exists, its content is read and compared numerically to the value of - the versioning attribute in the document that updates it. - If the version number in the new document is higher than in the document that - already exists in the database, then the operation is performed normally. +- `versionAttribute`: + You can use the `versionAttribute` option for external versioning support. + If set, the attribute with the name specified by the option is looked up in the + stored document and the attribute value is compared numerically to the value of + the versioning attribute in the supplied document that is supposed to update it. + + If the version number in the new document is higher (rounded down to a whole number) + than in the document that already exists in the database, then the update + operation is performed normally. This is also the case if the new versioning + attribute has a non-numeric value, if it is a negative number, or if the + attribute doesn't exist in the supplied or stored document. + If the version number in the new document is lower or equal to what exists in - the database, the operation is not performed and behaves like a no-op. No error - is returned in this case. + the database, the operation is not performed and the existing document thus not + changed. No error is returned in this case. + + The attribute can only be a top-level attribute. + + You can check if `_oldRev` and `_rev` are different to determine if the + document has been changed. --- diff --git a/site/content/3.12/release-notes/version-3.12/api-changes-in-3-12.md b/site/content/3.12/release-notes/version-3.12/api-changes-in-3-12.md index 41079b5c54..f4029765f8 100644 --- a/site/content/3.12/release-notes/version-3.12/api-changes-in-3-12.md +++ b/site/content/3.12/release-notes/version-3.12/api-changes-in-3-12.md @@ -241,13 +241,21 @@ for details. #### Document API -The `PUT /_api/document/{collection}/{key}` and `PATCH /_api/document/{collection}/{key}` -endpoints accept a new `versionAttribute` property that adds external versioning -support. -If set, the attribute with the name specified by the property is looked up in -the document to be replaced or updated and its content is read and compared -numerically to the value of the versioning attribute in the document that -updates or replaces it. +The following endpoints accept a new `versionAttribute` query parameter that adds +external versioning support: + +- `PATCH /_api/document/{collection}/{key}` (single document update) +- `PATCH /_api/document/{collection}` (multiple document update) +- `PUT /_api/document/{collection}` (single document replace) +- `PUT /_api/document/{collection}/{key}` (multiple document replace) +- `POST /_api/document/{collection}` (single document insert, when used to update/replace a document) +- `POST /_api/document/{collection}/{key}` (multiple document insert, when used to update/replace a document) + +If set, the attribute with the name specified by the option is looked up in the +stored document and the attribute value is compared numerically to the value of +the versioning attribute in the supplied document that is supposed to update/replace it. +The document is only changed if the new number is higher. See the +[Document API](../../develop/http-api/documents.md#create-a-document) for details. #### Index API @@ -425,21 +433,19 @@ Users of the JavaScript-based traversal API should use ### `collection` object -`collection.replace(object, data, options)` and -`collection.update(object, data, options)` now have an optional -`versionAttribute` property that adds external versioning support. It can also -be used for `collection.insert(data, options)` with `overwriteMode: "update"` -or `overwriteMode: "replace"`. - -If set, the attribute with the name specified by the property is looked up in -the document to be replaced or updated and its content is read and compared -numerically to the value of the versioning attribute in the document that -updates or replaces it. -If the version number in the new document is higher than in the document that -already exists in the database, then the operation is performed normally. -If the version number in the new document is lower or equal to what exists in -the database, the operation is not performed and behaves like a no-op. No error -is returned in this case. +The following methods now accept a `versionAttribute` option that adds external +versioning support: + +- `collection.update(object, data, options)` +- `collection.replace(object, data, options)` +- `collection.insert(data, options)` when used to update/replace a document + +If set, the attribute with the name specified by the option is looked up in the +stored document and the attribute value is compared numerically to the value of +the versioning attribute in the supplied document that is supposed to update/replace it. +The document is only changed if the new number is higher. See the +[JavaScript API](../../develop/javascript-api/@arangodb/collection-object.md#collectioninsertdata--options) +for details. ### `@arangodb/pregel` package diff --git a/site/content/3.12/release-notes/version-3.12/whats-new-in-3-12.md b/site/content/3.12/release-notes/version-3.12/whats-new-in-3-12.md index c736c0e5b2..66311a2f3e 100644 --- a/site/content/3.12/release-notes/version-3.12/whats-new-in-3-12.md +++ b/site/content/3.12/release-notes/version-3.12/whats-new-in-3-12.md @@ -176,6 +176,83 @@ section, as well as in the **API** tab of Foxx services and Foxx routes that use The new version adds support for OpenAPI 3.x specifications in addition to Swagger 2.x compatibility. +## External versioning support + +Document operations that update or replace documents now support a `versionAttribute` option. +If set, the attribute with the name specified by the option is looked up in the +stored document and the attribute value is compared numerically to the value of +the versioning attribute in the supplied document that is supposed to update/replace it. +The document is only changed if the new number is higher. + +This simple versioning can help to avoid overwriting existing data with older +versions in case data is transferred from an external system into ArangoDB +and the copies are currently not in sync. + +This new feature is supported in AQL, the JavaScript API, and the HTTP API for +the respective operations to update and replace documents, including the insert +operations when used to update/replace a document with `overwriteMode: "update"` +or `overwriteMode: "replace"`. + +**Examples:** + +Insert a new document normally using _arangosh_: + +```js +db.collection.insert({ _key: "123", externalVersion: 1 }); +``` + +Update the document if the versioning attribute is higher in the new document, +which is true in this case: + +```js +db.collection.update("123", + { externalVersion: 5, anotherAttribute: true }, + { versionAttribute: "externalVersion" }); +``` + +Updating the document is skipped if the versioning attribute is lower or equal +in the supplied document compared to what is currently stored in ArangoDB: + +```js +db.collection.update("123", + { externalVersion: 4, anotherAttribute: false }, + { versionAttribute: "externalVersion" }); +``` + +You can also make use of the `versionAttribute` option in an insert-update +operation for the update case, including in AQL: + +```js +db.collection.insert({ _key: "123", externalVersion: 6, value: "foo" }, + { overwriteMode: "update", versionAttribute: "externalVersion" }); + +db._query(`UPDATE { _key: "123", externalVersion: 7, value: "bar" } IN collection + OPTIONS { versionAttribute: "externalVersion"}`); +``` + +External versioning is opt-in and no version checking is performed for +operations for which the `versionAttribute` option isn't set. Document removal +operations do not support external versioning. Removal operations are always +carried out normally. + +Note that version checking is performed only if both the existing version of +the document in the database and the new document version contain the version +attribute with numeric values of `0` or greater. If neither the existing document +in the database nor the new document contains the version attribute, or if the +version attribute in any of the two is not a number inside the valid range, the +update/replace operations behave as if no version checking was requested. +This may overwrite the versioning attribute in the database. + +Also see: +- The AQL [INSERT](../../aql/high-level-operations/insert.md#versionattribute), + [UPDATE](../../aql/high-level-operations/update.md#versionattribute) and + [REPLACE](../../aql/high-level-operations/update.md#versionattribute) operations +- The `insert()`, `update()`, `replace()` methods of the + [_collection_ object](../../develop/javascript-api/@arangodb/collection-object.md#collectioninsertdata--options) + in the JavaScript API +- The endpoints to create, update, and replace a single or multiple documents + in the [HTTP API](../../develop/javascript-api/@arangodb/collection-object.md#collectioninsertdata--options) + ## AQL ### Improved joins @@ -365,78 +442,6 @@ The `move-filters-into-enumerate` optimizer rule can now also move filters into performance of queries that do a lot of filtering on longer lists of non-collection data. -### `versionAttribute` property for `UPDATE` and `REPLACE` operations - -`UPDATE` and `REPLACE` operations now support an optional `versionAttribute` -property. If set, the attribute with the name specified by the property is -looked up in the document to be updated or to be replaced. - -This simple versioning can help to avoid overwriting existing data with older -versions in case data is transferred from an external system into ArangoDB -and the copies are currently not in sync. - -The `versionAttribute` property can be used for `INSERT` operations with -`overwriteMode: "update"` or `overwriteMode: "replace"`. -It can also be used inside AQL queries by specifying it in the `OPTIONS` -clause of an `UPDATE`, `REPLACE`, and `INSERT` operation. - -If no such attribute exists, the operation is performed as usual. If such an -attribute exists, its content is read and compared numerically to the value of -the versioning attribute in the document that updates or replaces it. -If the version number in the new document is higher than in the document that -already exists in the database, then the operation is performed normally. -If the version number in the new document is lower or equal to what exists in -the database, the operation is not performed and behaves like a no-op. No error -is returned in this case. - -**Examples:** - -Inserts the new document normally: -```js -db.collection.insert({_key: "hello", value: 1, ver: 1}); -``` - -Updates the document because the value of the `versionAttribute` is higher in the -new document: -```js -db.collection.update("hello", - {value: 2, ver: 2}, - {versionAttribute: "ver"}); -``` - -Does not update the document because the value of the `versionAttribute` is lower -in the new document: -```js -db.collection.update("hello", - {value: 3, ver: 1}, - {versionAttribute: "ver"}); -``` - -Updates the document because the key already exists and the value of the -`versionAttribute` is higher in the new document: -```js -db.collection.insert({_key: "hello", value: 4, ver: 3}, - {overwriteMode: "update", versionAttribute: "ver"}); -``` - -```js -db._query("UPDATE 'hello' WITH {value: 5, ver: 4} IN collection - OPTIONS {versionAttribute: 'ver'}"); -``` - -Versioning is opt-in and no version checking is performed for -operations for which the `versionAttribute` property was not set as part of -the `UPDATE` and `REPLACE` operations or as an option in the AQL query. Document -removal operations do not support versioning. Removal operations are always -carried out normally without checking the version attribute, even if it is specified. - -Note that version checking is performed only if both the existing version of -the document in the database and the new document version contain the version -attribute with numeric values between `0` and `18446744073709551615`. -If neither the existing document in the database nor the new document version -does not contain the version attribute, or if the version attribute in any of -the two is not a number inside the valid range, the `UPDATE` and `REPLACE` operations behave as if no version checking was requested. - ### Improved late document materialization When `FILTER` operations can be covered by `primary`, `edge`, or `persistent`