collection.compute
Define a computed field.
A computed field dynamically derives the value of a field using a user-defined function. These fields aren’t persisted but are derived when the field is read.
The function is an anonymous function that is evaluated when a document is read. The anonymous function takes a source Document as input, operates on the document values, and returns a computed value. The following is an example of a computed function definition:
collection User {
compute fullName = (.firstName + " " + .lastName)
}
The example function is invoked using the following query and returns
Joe Bob
:
User.create({ firstName: "Joe", lastName: "Bob" }).fullName
An optional type can be included as part of the function signature.
Computed fields can be indexed to search for documents using a computed value. For example:
collection Account {
compute status = (
doc => (
if (oc.points > 100){
"gold"
}
else {
"standard"
}
)
)
}
index byStatus {terms [.status]}
Properties
Parameter | Type | Required | Description |
---|---|---|---|
fieldName |
Yes |
Computed field name. The fieldName can be the same as a persisted field name. An optional type can be declared for the function. |
|
functionBody |
Yes |
The function body is an anonymous function that is evaluated when a document is read. An optional type can also be provided as part of the function signature. The anonymous function takes a source Document as input, operates on the document values, and returns a computed value. Computed fields with defined anonymous functions can transform existing fields, provide convenient access to complex relations, and index over derived data. The anonymous function return value is the value of the computed field. |
Discussion
The computed_fields field defines document functions that evaluate a field when the document is read using the provided anonymous function. The anonymous function can:
-
read
-
cause other computed fields to be evaluated
-
call user-defined functions (UDFs).
A computed field anonymous function has the restriction that it can’t write to a document. Trying to write to a computed_fields field returns an error.
Computed fields take precedence over persisted fields, and persisted fields
can be referenced as children of the .data
field.
Computed fields and indexes
Computed fields can be indexed and when indexed, the value that is
indexed is the value of the computed field computed at the time the index is
built. Because of this, indexed computed fields have more restrictions
to prevent changes to the value of the field that are hard to detect. These
restrictions are enforced by the type system when changes are made to
computed fields or index definitions, preventing such changes. They are also
enforced at runtime when they cause evaluation of a computed field to fail
during the index build, which results in a null
term or value.
The following actions cause an index to be rebuilt:
-
Changes to the definition of an indexed computed field.
-
Removing the computed field. The new index treats the computed field like a persisted field.
When a new index entry is added or an existing entry is updated, the anonymous function computes the value at that time instead of every time the value is needed.
Computed fields can be indexed and used as unique constraints subject to the following restrictions, which cause the computed field evaluation to fail at index time because of an invalid index definition:
-
Indexed computed fields can’t use computed fields in the body.
-
Indexed computed fields can’t call UDFs.
-
Indexed computed fields can’t read.
Failing evaluation causes the document to emit a null
term or
value for the computed field.
The following table summarizes computed field index behavior:
Problem | Does the entry exist? |
---|---|
One or more values error, but terms are correct. Termless indexes count are always correct. |
Yes |
At least one term doesn’t error. |
Yes |
All terms error. |
No |
If an indexed computed field depends on another computed field, changing the definition of the first computed field silently changes the definition of the second.
Adding, updating, renaming, or removing non-indexed computed fields is safe. Changing an indexed computed field definition triggers a rebuild of its covering indexes.
Removing an indexed computed field is not allowed in protected mode.
Computed functions and types
Given the following schema, types are inferred on the index functions for the collection. For example:
collection User {
index byFullName {
terms [.fullName]
}
compute fullName: String = doc => "#{doc.firstName} #{doc.lastName}"
}
In a query, the type in the index function is inferred, and the following
query results in a Type error: 3 is not a subtype of String
error:
User.byFullName(3) // Type error: `3` is not a subtype of `String`
Examples
Define a computed field that validates a range of values
compute isAdult = (
doc => (doc.age > 18 && doc.age <= 120)
)
Assign a type to a computed field
Assign a String type to a computed field:
collection User {
compute status: String = doc => {
if (doc.points > 100) {
"gold"
} else {
"standard"
}
}
}
If the optional type is not provided, the type checker assigns the
enumeration of the possible computed values, which are gold
and standard
.
Limitations
Runtime errors in computed fields that are indexed aren’t reported. Computed
fields that result in runtime errors, including divide by zero, return null
.
If indexed, these computed fields are excluded from the index update.
Is this article helpful?
Tell Fauna how the article can be improved:
Visit Fauna's forums
or email docs@fauna.com
Thank you for your feedback!