FQL v4 will be decommissioned on June 30, 2025. Ensure that you complete your migration from FQL v4 to FQL v10 by that date. Fauna accounts created after August 21, 2024 must use FQL v10. These accounts will not be able to run FQL v4 queries or access the v4 Dashboard. For more details, see the v4 EOL announcement and migration guide. Contact support@fauna.com with any questions. |
Bindings
An index binding is a Lambda
function that computes the value
for a field in a document while the document is being indexed. Once
defined, the binding can be applied to the index’s terms
field, which
allows you to search for computed values, or to the index’s value
field, which allows you to return computed values for index matches.
For example, the documents that we are indexing might include a timestamp. We might want to be able to search for documents by date, or we might want to return the day of week for index matches.
Bindings must be pure Functions that cannot be used in bindings include: |
This tutorial assumes that you have successfully prepared your database by creating the necessary collections and documents. |
Create and use a binding
An index’s source
field defines one or more collections that should be
indexed. It is also used to define zero or more fields that have
associated binding functions. The binding functions compute the value
for the specified field while the document is being indexed.
Once a binding is defined, it must be used at least once in either the
index’s terms
or values
fields, or an error occurs: a binding
definition without use would cause unnecessary computation.
Let’s create an index for the People
collection (that we
created previously) that
specifies a binding function. Our binding function calculates the
"rolodex letter" for each person, which is the first letter of their
last name.
CreateIndex({
name: "people_by_rolodex",
source: {
collection: Collection("People"),
fields: {
rolodex: Query(
Lambda(
"doc",
SubString(Select(["data", "last"], Var("doc")), 0, 1)
)
)
}
},
terms: [ { binding: "rolodex" }],
values: [
{ binding: "rolodex" },
{ field: ["data", "last"] },
{ field: ["ref"] }
]
})
The highlights of this query:
-
The index is called
people_by_rolodex
. -
The
source
field specifies that:-
Documents within the
People
collection should be indexed. -
The field
rolodex
(which does not have to exist in any document in the collection) has a Lambda function, -
The
Query
function defers execution of the Lambda function until a document needs to be indexed. -
The Lambda function itself accepts the current document as a variable called
doc
. Then it returns the first letter of the document’slast
field using theSubString
function. TheSelect
function is used to extract thelast
field from the document.
-
-
The
terms
field specifies that therolodex
binding’s result is to be used for searching this index. -
The
values
field specifies that therolodex
binding’s result is to be included for index matches, along with the document’s Reference.
When you run this query, the output should be similar to:
{ ref: Index("people_by_rolodex"),
ts: 1580948872710000,
active: true,
serialized: true,
name: 'people_by_rolodex',
source:
{ collection: Collection("People"),
fields:
{ rolodex:
Query(Lambda("doc", Substring(Select(["data", "last"], Var("doc")), 0, 1))) } },
terms: [ { binding: 'rolodex' } ],
values:
[ { binding: 'rolodex' },
{ field: [ 'data', 'last' ] },
{ field: [ 'ref' ] } ],
partitions: 1 }
Now we can find people by their "rolodex letter". Copy the following query, paste it into the Shell, and run it:
Paginate(Match(Index("people_by_rolodex"), "C"))
The output should be similar to:
{
data: [
["C", "Cook", Ref(Collection("People"), "239535822978682381")],
["C", "Cook", Ref(Collection("People"), "239535822978684429")]
]
}
Search for empty fields
One specific use of bindings that you might find to be very useful is to
locate empty fields. Fauna does not store empty fields, and you
cannot directly use null
with the Match
function.
For example, with the following index:
CreateIndex({
name: "people_by_letter",
source: Collection("People"),
terms: [ { field: ["data", "letter"] } ]
})
We can search for people by letter:
Paginate(Match(Index("people_by_letter"), "A"))
{ data: [ Ref(Collection("People"), "240166254282805769") ] }
However, we cannot search for empty values using this index:
Paginate(Match(Index("people_by_letter"), null))
{ data: [] }
Why does this happen? When we pass null
to the Match
function,
the query compares the indexed field values to null
. A field that is
not set has no value at all, whereas null
is a value: the two don’t
match. Alternately, if we do not pass a value to Match
, there is an
empty comparison value to compare with the index’s terms
fields. Since
none of the indexed entries is lacking a terms
field, none of the
indexed entries matches the empty comparison value.
Instead, we can create a binding that tells us when a field is unset:
CreateIndex({
name: "people_by_null_letter",
source: [{
collection: Collection("People"),
fields: {
null_letter: Query(
Lambda(
"doc",
Equals(Select(["data", "letter"], Var("doc"), null), null)
)
)
}
}],
terms: [ {binding: "null_letter"} ],
})
The highlights for this query:
-
The index is named
people_by_null_letter
. -
The
source
is thePeople
collection. -
A binding for the field
null_letter
is defined. -
The binding function:
-
Accepts the indexed document in the
doc
variable. -
Uses the
Select
function to pull out theletter
field, and to usenull
as the default value is the field is unset. -
Uses the
Equals
function to compare the value of theletter
field withnull
. The result of calling this function is the implicit return value for the binding function, and that value is eithertrue
orfalse
.
-
-
The
terms
field specifies the binding function’s return value as a search term.
With this index in place, we can now search for People
documents that
have unset letter
fields:
Map(
Paginate(Match(Index("people_by_null_letter"), true)),
Lambda("X", Get(Var("X")))
)
{
data: [
{
ref: Ref(Collection("People"), "240166254282803721"),
ts: 1580867425600000,
data: {
first: "Leslie",
last: "Lamport",
degrees: ["BS", "MA", "PhD"]
}
}
]
}
Conclusion
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!