8000 DOC-123 | Document computed attributes APM-199 (part 2) (#1065) · arangodb/docs@2514006 · GitHub
[go: up one dir, main page]

Skip to content
This repository was archived by the owner on Dec 13, 2023. It is now read-only.

Commit 2514006

Browse files
Simran-Bansoboleva
andauthored
DOC-123 | Document computed attributes APM-199 (part 2) (#1065)
* Initial docs * WIP * WIP * Examples, corrections * Line continuation in examples * Fix examples, minor corrections * Minor tweak * Rename override to overwrite * Feedback from Jan * Update examples for 3.10 in computed-values at 2022-08-01T15:02:45+00:00 Co-authored-by: ansoboleva <93702078+ansoboleva@users.noreply.github.com> Co-authored-by: arangodb-release-bot <anastasia.soboleva@arangodb.com>
1 parent 154b8e3 commit 2514006

File tree

444 files changed

+12692
-6267
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

444 files changed

+12692
-6267
lines changed

3.10/data-modeling-documents-computed-values.md

Lines changed: 183 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ description: >-
66
---
77
# Computed Values
88

9+
<small>Introduced in: v3.10.0</small>
10+
911
{{ page.description }}
1012
{:class="lead"}
1113

12-
<small>Introduced in: v3.10.0</small>
13-
1414
If you want to add default values to new documents, maintain auxiliary
1515
attributes for search queries, or similar, you can set these attributes manually
1616
in every operation that inserts or modifies documents. However, it is more
@@ -28,15 +28,24 @@ every document, or to automatically combine multiple attributes into one,
2828
possibly with filtering and a conversion to lowercase characters, to then index
2929
the attribute and use it to perform case-insensitive searches.
3030

31+
## Using Computed Values
32+
33+
Computed values are defined per collection using the `computedValues` property,
34+
either when creating the collection or by modifying the collection later on.
35+
If you add or modify computed value definitions at a later point, then they only
36+
affect subsequent write operations. Existing documents remain in their state.
37+
38+
Computed value definitions are included in dumps, and the attributes they added,
39+
too, but no expressions are executed when restoring dumps. The collections and
40+
documents are restored as they are in the dump and no attributes are recalculated.
41+
3142
## JavaScript API
3243

33-
Computed values are defined per collection, either when creating the collection
34-
or by modifying the collection later on. The collection property is called
35-
`computedFields` and accepts an array of objects.
44+
The `computedValues` collection property accepts an array of objects.
3645

37-
`db._create(<collection-name>, { computedFields: [ { … }, … ] })`
46+
`db._create(<collection-name>, { computedValues: [ { … }, … ] })`
3847

39-
`db.<collection-name>.properties({ computedFields: [ { … }, … ] })`
48+
`db.<collection-name>.properties({ computedValues: [ { … }, … ] })`
4049

4150
Each object represents a computed value and can have the following attributes:
4251

@@ -50,21 +59,29 @@ Each object represents a computed value and can have the following attributes:
5059
See [Computed Value Expressions](#computed-value-expressions) for details.
5160

5261
- `overwrite` (boolean, _required_):
53-
Whether the computed value shall take precedence over a user-provided or
54-
existing attribute.
62+
Whether the target attribute shall be set if the expression evaluates to `null`.
63+
You can set the option to `false` to not set (or unset) the target attribute if
64+
the expression returns `null`. The default is `true`.
5565

5666
- `computeOn` (array, _optional_):
5767
An array of strings to define on which write operations the value shall be
5868
computed. The possible values are `"insert"`, `"update"`, and `"replace"`.
5969
The default is `["insert", "update", "replace"]`.
6070

6171
- `keepNull` (boolean, _optional_):
62-
Whether the result of the expression shall be stored if it evaluates to `null`.
63-
This can be used to skip the value computation if any pre-conditions are not met.
72+
Whether the target attribute shall be set if the expression evaluates to `null`.
73+
You can set the option to `false` to not set (or unset) the target attribute if
74+
the expression returns `null`. The default is `true`.
75+
76+
- `failOnWarning` (boolean, _optional_):
77+
Whether to let the write operation fail if the expression produces a warning.
78+
The default is `false`.
6479

65-
If you add, remove, or modify computed value definitions at a later point, they
66-
are only applied to subsequent write operations and older documents remain in
67-
their state.
80+
## HTTP API
81+
82+
See the `computedValues` collection property in the HTTP API documentation for
83+
[Creating Collections](http/collection-creating.html) and
84+
[Modifying Collections](http/collection-modifying.html).
6885

6986
## Computed Value Expressions
7087

@@ -76,14 +93,14 @@ You can access the document data via the `@doc` bind variable. It contains the
7693
data as it will be stored, including the `_key`, `_id`, and `_rev`
7794
system attributes. On inserts, you get the user-provided values (plus the
7895
system attributes), and on modifications, you get the updated or replaced
79-
document to work with.
80-
81-
Computed value expressions have the following requirements:
96+
document to work with, including the user-provided values.
8297

83-
- The expression must start with a `RETURN` statement.
98+
Computed value expressions have the following properties:
8499

85-
- No `FOR` loops, `LET` statements, and subqueries are allowed in the expression.
86-
`FOR` loops can be substituted using the [array expansion operator `[*]`](aql/advanced-array-operators.html#inline-expressions),
100+
- The expression must start with a `RETURN` operation and cannot contain any
101+
other operations. No `FOR` loops, `LET` statements, and subqueries are allowed
102+
in the expression. `FOR` loops can be substituted using the
103+
[array expansion operator `[*]`](aql/advanced-array-operators.html#inline-expressions),
87104
for example, with an inline expressions like the following:
88105

89106
`RETURN @doc.values[* FILTER CURRENT > 42 RETURN CURRENT * 2]`
@@ -93,9 +110,15 @@ Computed value expressions have the following requirements:
93110
be used in the expression (e.g. `DOCUMENT()`, `PREGEL_RESULT()`,
94111
`COLLECTION_COUNT()`).
95112

96-
- You cannot base a computed value on another. If you reference an attribute
97-
that results from another computed value, the value is implicitly `null`,
98-
like any access of non-existent attributes.
113+
- You cannot access the result of another computed value that is generated on
114+
the same `computeOn` event.
115+
116+
For example, two computed values that are generated on `insert` can not see
117+
the result of the other. Referencing the attributes results in an implicit
118+
`null` value. Computed values that are generated on `update` or `replace` can
119+
see the results of the previous `insert` computations, however. They cannot
120+
see the new values of other `update` and `replace` computations, regardless of
121+
the order of the computed value definitions in the `computedValues` property.
99122

100123
- You can use AQL functions in the expression but only those that can be
101124
executed on DB-Servers, regardless of your deployment type. The following
@@ -117,10 +140,142 @@ Computed value expressions have the following requirements:
117140
- `FULLTEXT()`
118141
- [User-defined functions (UDFs)](aql/extending.html)
119142

120-
<!-- TODO
121-
When using arangodump to restore data into a collection with computed attributes defined, the restore does not recalculate the computed values, but will restore the documents as they are contained inside the dump.
143+
Expressions that do not meet the requirements or that are syntactically invalid
144+
are rejected immediately, when setting or modifying the computed value definitions
145+
of a collection.
146+
147+
## Examples
148+
149+
Add an attribute with the creation timestamp to new documents:
150+
151+
{% arangoshexample examplevar="examplevar" script="script" result="result" %}
152+
@startDocuBlockInline computedValuesCreatedAt
153+
@EXAMPLE_ARANGOSH_OUTPUT{computedValuesCreatedAt}
154+
| var coll = db._create("users", {
155+
| computedValues: [
156+
| {
157+
| name: "createdAt",
158+
| expression: "RETURN DATE_NOW()",
159+
| overwrite: true,
160+
| computeOn: ["insert"]
161+
| }
162+
| ]
163+
});
164+
var doc = db.users.save({ name: "Paula Plant" });
165+
db.users.toArray();
166+
~ db._drop("users");
167+
@END_EXAMPLE_ARANGOSH_OUTPUT
168+
@endDocuBlock computedValuesCreatedAt
169+
{% endarangoshexample %}
170+
{% include arangoshexample.html id=examplevar script=script result=result %}
171+
172+
Add an attribute with the date and time of the last modification, only taking
173+
update and replace operations into (not inserts), and allowing to manually
174+
set this value instead of using the computed value:
175+
176+
{% arangoshexample examplevar="examplevar" script="script" result="result" %}
177+
@startDocuBlockInline computedValuesModifiedAt
178+
@EXAMPLE_ARANGOSH_OUTPUT{computedValuesModifiedAt}
179+
| var coll = db._create("users", {
180+
| computedValues: [
181+
| {
182+
| name: "modifiedAt",
183+
| expression: "RETURN ZIP(['date', 'time'], SPLIT(DATE_ISO8601(DATE_NOW()), 'T'))",
184+
| overwrite: false,
185+
| computeOn: ["update", "replace"]
186+
| }
187+
| ]
188+
});
189+
var doc = db.users.save({ _key: "123", name: "Paula Plant" });
190+
doc = db.users.update("123", { email: "gardener@arangodb.com" });
191+
db.users.toArray();
192+
doc = db.users.update("123", { email: "greenhouse@arangodb.com", modifiedAt: { date: "2019-01-01", time: "20:30:00.000Z" } });
193+
db.users.toArray();
194+
~ db._drop("users");
195+
@END_EXAMPLE_ARANGOSH_OUTPUT
196+
@endDocuBlock computedValuesModifiedAt
197+
{% endarangoshexample %}
198+
{% include arangoshexample.html id=examplevar script=script result=result %}
199+
200+
Compute an attribute from two arrays, filtering one of the lists, and calculating
201+
new values to implement a case-insensitive search using a persistent array index:
202+
203+
{% arangoshexample examplevar="examplevar" script="script" result="result" %}
204+
@startDocuBlockInline computedValuesCombine
205+
@EXAMPLE_ARANGOSH_OUTPUT{computedValuesCombine}
206+
| var coll = db._create("users", {
207+
| computedValues: [
208+
| {
209+
| name: "searchTags",
210+
| expression: "RETURN APPEND(@doc.is[* FILTER CURRENT.public == true RETURN LOWER(CURRENT.name)], @doc.loves[* RETURN LOWER(CURRENT)])",
211+
| overwrite: true
212+
| }
213+
| ]
214+
});
215+
var doc = db.users.save({ name: "Paula Plant", is: [ { name: "Gardener", public: true }, { name: "female" } ], loves: ["AVOCADOS", "Databases"] });
216+
var idx = db.users.ensureIndex({ type: "persistent", fields: ["searchTags[*]"] });
217+
db._query(`FOR u IN users FILTER "avocados" IN u.searchTags RETURN u`).toArray();
218+
~ db._drop("users");
219+
@END_EXAMPLE_ARANGOSH_OUTPUT
220+
@endDocuBlock computedValuesCombine
221+
{% endarangoshexample %}
222+
{% include arangoshexample.html id=examplevar script=script result=result %}
223+
224+
Set `keepNull` to `false` and let an expression return `null` to not set or
225+
unset the target attribute. If you set `overwrite` to `false` at the same time,
226+
then the target attribute is not actively unset:
227+
228+
{% arangoshexample examplevar="examplevar" script="script" result="result" %}
229+
@startDocuBlockInline computedValuesKeepNull
230+
@EXAMPLE_ARANGOSH_OUTPUT{computedValuesKeepNull}
231+
| var coll = db._create("users", {
232+
| computedValues: [
233+
| {
234+
| name: "fullName",
235+
| expression: "RETURN @doc.firstName != null AND @doc.lastName != null ? CONCAT_SEPARATOR(' ', @doc.firstName, @doc.lastName) : null",
236+
| overwrite: false,
237+
| keepNull: false
238+
| }
239+
| ]
240+
});
241+
| var docs = db.users.save([
242+
| { firstName: "Paula", lastName: "Plant" },
243+
| { firstName: "James" },
244+
| { lastName: "Barrett", fullName: "Andy J. Barrett" }
245+
]);
246+
db.users.toArray();
247+
~ db._drop("users");
248+
@END_EXAMPLE_ARANGOSH_OUTPUT
249+
@endDocuBlock computedValuesKeepNull
250+
{% endarangoshexample %}
251+
{% include arangoshexample.html id=examplevar script=script result=result %}
122252

123-
Values of computed attributes are properly replicated to followers. Followers will receive the documents as they are stored on the leader, including any computed attributes. Followers will not rerun the computed attributes computations themselves.
253+
Add a computed value as a sub-attribute to documents. This is not possible
254+
directly because the target attribute needs to be a top-level attribute, but the
255+
AQL expression can merge a nested object with the top-level attribute to achieve
256+
this. The expression checks whether the attributes it wants to calculate a new
257+
value from exist and are strings. If the preconditions are not met, then it
258+
returns the original `name` attribute:
124259

125-
Non-deterministic computation expressions, such as RETURN RAND() will still work correctly, so that leaders and followers will have the same value for the computed attribute. This is achieved by leaders replicating the document data including the computed attributes values, and the followers not carrying out the computation again.
126-
-->
260+
{% arangoshexample examplevar="examplevar" script="script" result="result" %}
261+
@startDocuBlockInline computedValuesSubattribute
262+
@EXAMPLE_ARANGOSH_OUTPUT{computedValuesSubattribute}
263+
| var coll = db._create("users", {
264+
| computedValues: [
265+
| {
266+
| name: "name",
267+
| expression: "RETURN IS_STRING(@doc.name.first) AND IS_STRING(@doc.name.last) ? MERGE(@doc.name, { 'full': CONCAT_SEPARATOR(' ', @doc.name.first, @doc.name.last) }) : @doc.name",
268+
| overwrite: true // must be true to replace the top-level "name" attribute
269+
| }
270+
| ]
271+
});
272+
| var docs = db.users.save([
273+
| { name: { first: "James" } },
274+
| { name: { first: "Paula", last: "Plant" } }
275+
]);
276+
db.users.toArray();
277+
~ db._drop("users");
278+
@END_EXAMPLE_ARANGOSH_OUTPUT
279+
@endDocuBlock computedValuesSubattribute
280+
{% endarangoshexample %}
281+
{% include arangoshexample.html id=examplevar script=script result=result %}

0 commit comments

Comments
 (0)
0