Temporality
In this tutorial, we explore Fauna’s temporal features.
Temporal queries show you exactly how data has changed over time. You can ask for instances that have been updated in the last few days, and even scope whole queries to a point in the past, querying a snapshot of the database before and after particular transactions were processed.
This tutorial assumes that you have completed the Dashboard quick start. |
Step 1: Open the Fauna Dashboard
Log in to the Fauna Dashboard and click the database my_db
in your
list of databases.
Step 2: Open the Dashboard’s Shell
Click SHELL in the left sidebar to display the Dashboard’s Shell.
Step 3: Create a collection and 2 indexes
We need a collection to store our data, and 2 indexes that help us explore the data. For our temporal features exploration, we’ll create a collection of shapes, a collection index that makes it easy to review all of our shapes, and a term-based index that makes it easy to lookup a shape by its name. Run the following query in the shell:
CreateCollection({ name: "shapes" })
CreateIndex({ name: "all_shapes", source: Collection("shapes") })
+
CreateIndex({
name: "shapes_by_name",
source: Collection("shapes"),
unique: true,
terms: [{ field: ["data", "name"] }]
})
Step 4: Create the first set of shape documents
Now we can create some shapes. Each shape has a name and a color.
Foreach(
[
["triangle", "yellow"],
["square", "green"],
["circle", "blue"]
],
Lambda("shape",
Create(Collection("shapes"), { data: {
name: Select(0, Var("shape")),
color: Select(1, Var("shape"))
}})
)
)
Step 5: Create a second set of shape documents
After a short delay, run the following query to create some additional shapes. The delay only needs to be a few seconds; the delay gives this second set of shapes a different creation timestamp.
Foreach(
[
["pentagon", "black"],
["hexagon", "cyan"],
["octagon", "red"]
],
Lambda("shape",
Create(Collection("shapes"), { data: {
name: Select(0, Var("shape")),
color: Select(1, Var("shape"))
}})
)
)
Step 6: Review the shapes
With our shapes created, let’s query Fauna to see our shape documents, and access their creation timestamps.
Map(
Paginate(
Match(Index("all_shapes"))
),
Lambda("X", Get(Var("X")))
)
You should see output similar to:
{ data:
[ { ref: Ref(Collection("shapes"), "232990372366647808"),
ts: 1558455784100000,
data: { name: 'square', color: 'green' } },
{ ref: Ref(Collection("shapes"), "232990372366648832"),
ts: 1558455784100000,
data: { name: 'circle', color: 'blue' } },
{ ref: Ref(Collection("shapes"), "232990372366649856"),
ts: 1558455784100000,
data: { name: 'triangle', color: 'yellow' } },
{ ref: Ref(Collection("shapes"), "232990436517478912"),
ts: 1558455845280000,
data: { name: 'pentagon', color: 'black' } },
{ ref: Ref(Collection("shapes"), "232990436517479936"),
ts: 1558455845280000,
data: { name: 'octagon', color: 'red' } },
{ ref: Ref(Collection("shapes"), "232990436517480960"),
ts: 1558455845280000,
data: { name: 'hexagon', color: 'cyan' } } ] }
The Notice that the timestamps for each group of shapes are the same. Fauna processes each transaction so that all write effects appear to occur at the same moment. The values you see in your output should be different than shown here. |
Step 7: Change some data
Since Fauna’s temporal features let you see how data has changed over time, let’s make some changes. Suppose we no longer want the black pentagon, and the circle should have been white. We can make those changes with the following queries:
Delete(Ref(Collection("shapes"), "232990436517478912"))
Update(
Select("ref", Get(Match(Index("shapes_by_name"), "circle"))),
{ data: { color: "white" }}
)
Step 8: Review the shapes
Let’s run the review query again, so that we can see the effect of our changes.
Map(
Paginate(
Match(Index("all_shapes"))
),
Lambda("X", Get(Var("X")))
)
You should see output similar to:
{ data:
[ { ref: Ref(Collection("shapes"), "232990372366647808"),
ts: 1558455784100000,
data: { name: 'square', color: 'green' } },
{ ref: Ref(Collection("shapes"), "232990372366648832"),
ts: 1558456119830000,
data: { name: 'circle', color: 'white' } },
{ ref: Ref(Collection("shapes"), "232990372366649856"),
ts: 1558455784100000,
data: { name: 'triangle', color: 'yellow' } },
{ ref: Ref(Collection("shapes"), "232990436517479936"),
ts: 1558455845280000,
data: { name: 'octagon', color: 'red' } },
{ ref: Ref(Collection("shapes"), "232990436517480960"),
ts: 1558455845280000,
data: { name: 'hexagon', color: 'cyan' } } ] }
Good! The black pentagon is no longer listed, and our circle shape is now white.
Step 9: Temporal feature #1: Snapshots
Fauna’s snapshot feature lets you query your database to see the
state of your data at a particular point in time. To review a snapshot
of our shapes after the first group was created, but before the
second group was created, we wrap our review query in the At
function, and use the smaller of the two timestamps.
The timestamp in the query below needs to be updated, since
it reflects the time when this tutorial was written. Any
timestamp between when you created the first group of shapes
and the creation of the second group of shapes would work for
this demonstration. However, it is easiest to replace
1558455784100000 in the query below with the timestamp
reported in your output for the square shape.
|
At(
1558455784100000,
Map(
Paginate(
Match(Index("all_shapes"))
),
Lambda("X", Get(Var("X")))
)
)
You should see output similar to:
{ data:
[ { ref: Ref(Collection("shapes"), "232990372366647808"),
ts: 1558455784100000,
data: { name: 'square', color: 'green' } },
{ ref: Ref(Collection("shapes"), "232990372366648832"),
ts: 1558455784100000,
data: { name: 'circle', color: 'blue' } },
{ ref: Ref(Collection("shapes"), "232990372366649856"),
ts: 1558455784100000,
data: { name: 'triangle', color: 'yellow' } } ] }
Only the first group of shapes is returned, since at the timestamp we specified, the second group had not been created, nor had the circle been updated to be white.
At is inclusive, which means that any documents created
before, and up to and including the specified timestamp are
evaluated in the provided query expression.
|
Step 10: Temporal feature #2: Events
Fauna never changes a stored document. Any updates you make creates a new copy of the document containing the changes, and the original document remains unchanged. That means, for the circle shape, Fauna has two copies of the circle shape, one when it was blue, and the other when it was white.
We can see the history of a document by using the Events
function.
Paginate(
Events(
Select(
"ref",
Get(Match(Index("shapes_by_name"), "circle"))
)
)
)
You should see output similar to:
{ data:
[ { ts: 1558455784100000,
action: 'create',
instance: Ref(Collection("shapes"), "232990372366648832"),
data: { name: 'circle', color: 'blue' } },
{ ts: 1558456119830000,
action: 'update',
instance: Ref(Collection("shapes"), "232990372366648832"),
data: { color: 'white' } } ] }
To explain the query, it is helpful to start at the right:
-
Get(Match(Index("shapes_by_name"), "circle"))
retrieves the circle shape. -
Select("ref", Get(…))
extracts theref
field from the circle’s document. -
Events(Select(…))
retrieves the set of events for the specified reference. -
Paginate(Events(…))
returns the materialized set of events.
Events
can provide the set of modifications for any kind of document
within Fauna. For user documents, the actions include create
,
insert
, remove
, replace
, update
, and delete. For indexes and
databases, the actions include add
and remove
.
Conclusion
In this tutorial, we have modeled some simple documents with differing timestamps, and learned how to query the state of the database at a snapshot, and how to see the history of a particular document.
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!