Using temporality
Overview
Fauna documents are immutable, which means that once a document is created it never changes. If you update a document Fauna creates a new version of the document reflecting the changes and the original is left intact. With Fauna’s temporality features, it is possible to see the change history of a document, retrieve older versions, and perform queries based on document timestamps.
The history_days
attribute
The history_days
field of the
collection determines how
long Fauna retains old versions of updated documents. history_days
defaults to 30, but it is possible to specify a different value when you
create a collection:
ObjectV(ref: RefV(id = "fruit", collection = RefV(id = "collections")),ts: LongV(1659484863560000),history_days: LongV(10),name: StringV(fruit))
map[history_days:10 name:fruit ref:{fruit 0x1400011d830 0x1400011d830 <nil>} ts:1659543812120000]
{ref: ref(id = "fruit", collection = ref(id = "collections")), ts: 1659631452280000, history_days: 10, name: "fruit"}
{
ref: Collection("fruit"),
ts: 1641495115580000,
history_days: 10,
name: "fruit"
}
{'ref': Ref(id=fruit, collection=Ref(id=collections)), 'ts': 1659634757630000, 'history_days': 10, 'name': 'fruit'}
{
ref: Collection("fruit"),
ts: 1659482501550000,
history_days: 10,
name: 'fruit'
}
You can also update the history_days
attribute of an existing
collection:
ObjectV(ref: RefV(id = "fruit", collection = RefV(id = "collections")),ts: LongV(1659484870670000),history_days: LongV(5),name: StringV(fruit))
map[history_days:5 name:fruit ref:{fruit 0x1400011d950 0x1400011d950 <nil>} ts:1659543814030000]
{ref: ref(id = "fruit", collection = ref(id = "collections")), ts: 1659631475020000, history_days: 5, name: "fruit"}
{
ref: Collection("fruit"),
ts: 1641495115580000,
history_days: 5,
name: "fruit"
}
{'ref': Ref(id=fruit, collection=Ref(id=collections)), 'ts': 1659634759800000, 'history_days': 5, 'name': 'fruit'}
{
ref: Collection("fruit"),
ts: 1659482502120000,
history_days: 5,
name: 'fruit'
}
After the period of time specified by history_days
expires, Fauna
removes any version of a document which has aged out. The most recent
version of a document is not affected.
Documents might also include a ttl
(time-to-live) field. Documents
that have aged out of the database due to a ttl
expiration cannot be
retrieved with temporal queries. See Create
for more information
about the ttl
attribute.
Document removal is handled by a background task, so once a
document "expires" due to the history_days setting on a
collection or the ttl field on a document, it could be some time
(hours or days) before the removal occurs. There is no guarantee
that removal actually occurs.
|
Document history
You can see a document’s change history with the Events
function.
To illustrate this feature, let’s create a new document in the fruit
collection:
ObjectV(ref: RefV(id = "1", collection = RefV(id = "fruit", collection = RefV(id = "collections"))),ts: LongV(1659484867110000),data: ObjectV(type: StringV(apple),colors: Arr(StringV(red), StringV(green)),quantity: LongV(15)))
map[data:map[colors:[red green] quantity:15 type:apple] ref:{1 0x1400011dbf0 0x1400011dbf0 <nil>} ts:1659543813060000]
{ref: ref(id = "1", collection = ref(id = "fruit", collection = ref(id = "collections"))), ts: 1659631463820000, data: {type: "apple", colors: ["red", "green"], quantity: 15}}
{
ref: Ref(Collection("fruit"), "1"),
ts: 1641328117890000,
data: { type: "apple", colors: ["red", "green"], quantity: 15 }
}
{'ref': Ref(id=1, collection=Ref(id=fruit, collection=Ref(id=collections))), 'ts': 1659634758720000, 'data': {'type': 'apple', 'colors': ['red', 'green'], 'quantity': 15}}
{
ref: Ref(Collection("fruit"), "1"),
ts: 1659482501840000,
data: { type: 'apple', colors: [ 'red', 'green' ], quantity: 15 }
}
Now let’s update the document:
ObjectV(ref: RefV(id = "1", collection = RefV(id = "fruit", collection = RefV(id = "collections"))),ts: LongV(1659484874200000),data: ObjectV(type: StringV(apple),colors: Arr(StringV(red), StringV(green)),quantity: LongV(50)))
map[data:map[colors:[red green] quantity:50 type:apple] ref:{1 0x1400020a300 0x1400020a300 <nil>} ts:1659543814960000]
{ref: ref(id = "1", collection = ref(id = "fruit", collection = ref(id = "collections"))), ts: 1659631486310000, data: {type: "apple", colors: ["red", "green"], quantity: 50}}
{
ref: Ref(Collection("fruit"), "1"),
ts: 1641328117890000,
data: { type: "apple", colors: ["red", "green"], quantity: 50 }
}
{'ref': Ref(id=1, collection=Ref(id=fruit, collection=Ref(id=collections))), 'ts': 1659634760860000, 'data': {'type': 'apple', 'colors': ['red', 'green'], 'quantity': 50}}
{
ref: Ref(Collection("fruit"), "1"),
ts: 1659482502400000,
data: { type: 'apple', colors: [ 'red', 'green' ], quantity: 50 }
}
Now you can use Events
to see the change history. The following
example uses Events
with the Paginate
function to list all the
document’s change events.
ObjectV(data: Arr(ObjectV(ts: LongV(1659484867110000),action: StringV(create),document: RefV(id = "1", collection = RefV(id = "fruit", collection = RefV(id = "collections"))),data: ObjectV(type: StringV(apple),colors: Arr(StringV(red), StringV(green)),quantity: LongV(15))), ObjectV(ts: LongV(1659484874200000),action: StringV(update),document: RefV(id = "1", collection = RefV(id = "fruit", collection = RefV(id = "collections"))),data: ObjectV(quantity: LongV(50)))))
map[data:[map[action:create data:map[colors:[red green] quantity:15 type:apple] document:{1 0x1400011db00 0x1400011db00 <nil>} ts:1659543813060000] map[action:update data:map[quantity:50] document:{1 0x1400011dd10 0x1400011dd10 <nil>} ts:1659543814960000]]]
{data: [{ts: 1659631463820000, action: "create", document: ref(id = "1", collection = ref(id = "fruit", collection = ref(id = "collections"))), data: {type: "apple", colors: ["red", "green"], quantity: 15}}, {ts: 1659631486310000, action: "update", document: ref(id = "1", collection = ref(id = "fruit", collection = ref(id = "collections"))), data: {quantity: 50}}]}
{
data: [
{
ts: 1644607325240000,
action: 'create',
document: Ref(Collection("fruit"), "1"),
data: { type: 'apple', colors: [ 'red', 'green' ], quantity: 15 }
},
{
ts: 1644607325510000,
action: 'update',
document: Ref(Collection("fruit"), "1"),
data: { quantity: 50 }
}
]
}
{'data': [{'ts': 1659634758720000, 'action': 'create', 'document': Ref(id=1, collection=Ref(id=fruit, collection=Ref(id=collections))), 'data': {'type': 'apple', 'colors': ['red', 'green'], 'quantity': 15}}, {'ts': 1659634760860000, 'action': 'update', 'document': Ref(id=1, collection=Ref(id=fruit, collection=Ref(id=collections))), 'data': {'quantity': 50}}]}
{
data: [
{
ts: 1659482501840000,
action: 'create',
document: Ref(Collection("fruit"), "1"),
data: { type: 'apple', colors: [ 'red', 'green' ], quantity: 15 }
},
{
ts: 1659482502400000,
action: 'update',
document: Ref(Collection("fruit"), "1"),
data: { quantity: 50 }
}
]
}
You can retrieve a specific version of a document by including its
timestamp with the Get
function:
ObjectV(ref: RefV(id = "1", collection = RefV(id = "fruit", collection = RefV(id = "collections"))),ts: LongV(1659484867110000),data: ObjectV(type: StringV(apple),colors: Arr(StringV(red), StringV(green)),quantity: LongV(15)))
map[data:map[colors:[red green] quantity:15 type:apple] ref:{1 0x1400007fb30 0x1400007fb30 <nil>} ts:1659630709950000]
{ref: ref(id = "1", collection = ref(id = "fruit", collection = ref(id = "collections"))), ts: 1659632352260000, data: {type: "apple", colors: ["red", "green"], quantity: 15}}
{
ref: Ref(Collection("fruit"), "1"),
ts: 1641838482800000,
data: {
type: "apple",
colors: ["red", "green"],
quantity: 15
}
}
{'ref': Ref(id=1, collection=Ref(id=fruit, collection=Ref(id=collections))), 'ts': 1659634930250000, 'data': {'type': 'apple', 'colors': ['red', 'green'], 'quantity': 15}}
{
ref: Ref(Collection("fruit"), "1"),
ts: 1659482760050000,
data: { type: 'apple', colors: [ 'red', 'green' ], quantity: 15 }
}
Replace the string <$TIMESTAMP>
with the value for ts
from the
document creation result.
Timestamp queries
You can use the At
function to retrieve data from a specified
point in time. To see this feature in action, let’s add a few more
documents to our collection.
Arr(ObjectV(ref: RefV(id = "2", collection = RefV(id = "fruit", collection = RefV(id = "collections"))),ts: LongV(1659484884950000),data: ObjectV(type: StringV(mango),colors: Arr(StringV(green), StringV(yellow)),quantity: LongV(20))), ObjectV(ref: RefV(id = "3", collection = RefV(id = "fruit", collection = RefV(id = "collections"))),ts: LongV(1659484884950000),data: ObjectV(type: StringV(melon),colors: Arr(StringV(green)),quantity: LongV(100))), ObjectV(ref: RefV(id = "4", collection = RefV(id = "fruit", collection = RefV(id = "collections"))),ts: LongV(1659484884950000),data: ObjectV(type: StringV(pear),colors: Arr(StringV(yellow), StringV(brown)),quantity: LongV(60))))
[map[data:map[colors:[green yellow] quantity:20 type:mango] ref:{2 0x1400011def0 0x1400011def0 <nil>} ts:1659630714510000] map[data:map[colors:[green] quantity:100 type:melon] ref:{3 0x140001a0120 0x140001a0120 <nil>} ts:1659630714510000] map[data:map[colors:[yellow brown] quantity:60 type:pear] ref:{4 0x140001a0330 0x140001a0330 <nil>} ts:1659630714510000]]
[{ref: ref(id = "2", collection = ref(id = "fruit", collection = ref(id = "collections"))), ts: 1659632408450000, data: {type: "mango", colors: ["green", "yellow"], quantity: 20}}, {ref: ref(id = "3", collection = ref(id = "fruit", collection = ref(id = "collections"))), ts: 1659632408450000, data: {type: "melon", colors: ["green"], quantity: 100}}, {ref: ref(id = "4", collection = ref(id = "fruit", collection = ref(id = "collections"))), ts: 1659632408450000, data: {type: "pear", colors: ["yellow", "brown"], quantity: 60}}]
[
{
ref: Ref(Collection("fruit"), "2"),
ts: 1659480507940000,
data: { type: 'mango', colors: [ 'green', 'yellow' ], quantity: 20 }
},
{
ref: Ref(Collection("fruit"), "3"),
ts: 1659480507940000,
data: { type: 'melon', colors: [ 'green' ], quantity: 100 }
},
{
ref: Ref(Collection("fruit"), "4"),
ts: 1659480507940000,
data: { type: 'pear', colors: [ 'yellow', 'brown' ], quantity: 60 }
}
]
[{'ref': Ref(id=2, collection=Ref(id=fruit, collection=Ref(id=collections))), 'ts': 1659635026440000, 'data': {'type': 'mango', 'colors': ['green', 'yellow'], 'quantity': 20}}, {'ref': Ref(id=3, collection=Ref(id=fruit, collection=Ref(id=collections))), 'ts': 1659635026440000, 'data': {'type': 'melon', 'colors': ['green'], 'quantity': 100}}, {'ref': Ref(id=4, collection=Ref(id=fruit, collection=Ref(id=collections))), 'ts': 1659635026440000, 'data': {'type': 'pear', 'colors': ['yellow', 'brown'], 'quantity': 60}}]
[
{
ref: Ref(Collection("fruit"), "2"),
ts: 1659482827030000,
data: { type: 'mango', colors: [ 'green', 'yellow' ], quantity: 20 }
},
{
ref: Ref(Collection("fruit"), "3"),
ts: 1659482827030000,
data: { type: 'melon', colors: [ 'green' ], quantity: 100 }
},
{
ref: Ref(Collection("fruit"), "4"),
ts: 1659482827030000,
data: { type: 'pear', colors: [ 'yellow', 'brown' ], quantity: 60 }
}
]
These new documents all have the same timestamp, because they were all added as part of the same transaction.
Now that you have several documents in our collection, create an index to retrieve them all at once:
ObjectV(data: Arr(ObjectV(ref: RefV(id = "1", collection = RefV(id = "fruit", collection = RefV(id = "collections"))),ts: LongV(1659484874200000),data: ObjectV(type: StringV(apple),colors: Arr(StringV(red), StringV(green)),quantity: LongV(50))), ObjectV(ref: RefV(id = "2", collection = RefV(id = "fruit", collection = RefV(id = "collections"))),ts: LongV(1659484884950000),data: ObjectV(type: StringV(mango),colors: Arr(StringV(green), StringV(yellow)),quantity: LongV(20))), ObjectV(ref: RefV(id = "3", collection = RefV(id = "fruit", collection = RefV(id = "collections"))),ts: LongV(1659484884950000),data: ObjectV(type: StringV(melon),colors: Arr(StringV(green)),quantity: LongV(100))), ObjectV(ref: RefV(id = "4", collection = RefV(id = "fruit", collection = RefV(id = "collections"))),ts: LongV(1659484884950000),data: ObjectV(type: StringV(pear),colors: Arr(StringV(yellow), StringV(brown)),quantity: LongV(60)))))
map[data:[map[data:map[colors:[red green] quantity:50 type:apple] ref:{1 0x1400007fd70 0x1400007fd70 <nil>} ts:1659630711770000] map[data:map[colors:[green yellow] quantity:20 type:mango] ref:{2 0x1400007ff80 0x1400007ff80 <nil>} ts:1659630714510000] map[data:map[colors:[green] quantity:100 type:melon] ref:{3 0x1400016a1b0 0x1400016a1b0 <nil>} ts:1659630714510000] map[data:map[colors:[yellow brown] quantity:60 type:pear] ref:{4 0x1400016a3c0 0x1400016a3c0 <nil>} ts:1659630714510000]]]
{data: [{ref: ref(id = "1", collection = ref(id = "fruit", collection = ref(id = "collections"))), ts: 1659632699290000, data: {type: "apple", colors: ["red", "green"], quantity: 50}}, {ref: ref(id = "2", collection = ref(id = "fruit", collection = ref(id = "collections"))), ts: 1659632733620000, data: {type: "mango", colors: ["green", "yellow"], quantity: 20}}, {ref: ref(id = "3", collection = ref(id = "fruit", collection = ref(id = "collections"))), ts: 1659632733620000, data: {type: "melon", colors: ["green"], quantity: 100}}, {ref: ref(id = "4", collection = ref(id = "fruit", collection = ref(id = "collections"))), ts: 1659632733620000, data: {type: "pear", colors: ["yellow", "brown"], quantity: 60}}]}
{
data: [
{
ref: Ref(Collection("fruit"), "1"),
ts: 1641578425510000,
data: { type: 'apple', colors: [ 'red', 'green' ], quantity: 50 }
},
{
ref: Ref(Collection("fruit"), "2"),
ts: 1641592193100000,
data: { type: 'mango', colors: [ 'green', 'yellow' ], quantity: 20 }
},
{
ref: Ref(Collection("fruit"), "3"),
ts: 1641592193100000,
data: { type: 'melon', colors: [ 'green' ], quantity: 100 }
},
{
ref: Ref(Collection("fruit"), "4"),
ts: 1641592193100000,
data: { type: 'pear', colors: [ 'yellow', 'brown' ], quantity: 60 }
},
]
}
{'data': [{'ref': Ref(id=1, collection=Ref(id=fruit, collection=Ref(id=collections))), 'ts': 1659635074010000, 'data': {'type': 'apple', 'colors': ['red', 'green'], 'quantity': 50}}, {'ref': Ref(id=2, collection=Ref(id=fruit, collection=Ref(id=collections))), 'ts': 1659635077080000, 'data': {'type': 'mango', 'colors': ['green', 'yellow'], 'quantity': 20}}, {'ref': Ref(id=3, collection=Ref(id=fruit, collection=Ref(id=collections))), 'ts': 1659635077080000, 'data': {'type': 'melon', 'colors': ['green'], 'quantity': 100}}, {'ref': Ref(id=4, collection=Ref(id=fruit, collection=Ref(id=collections))), 'ts': 1659635077080000, 'data': {'type': 'pear', 'colors': ['yellow', 'brown'], 'quantity': 60}}]}
{
data: [
{
ref: Ref(Collection("fruit"), "1"),
ts: 1659482826190000,
data: { type: 'apple', colors: [ 'red', 'green' ], quantity: 50 }
},
{
ref: Ref(Collection("fruit"), "2"),
ts: 1659482827030000,
data: { type: 'mango', colors: [ 'green', 'yellow' ], quantity: 20 }
},
{
ref: Ref(Collection("fruit"), "3"),
ts: 1659482827030000,
data: { type: 'melon', colors: [ 'green' ], quantity: 100 }
},
{
ref: Ref(Collection("fruit"), "4"),
ts: 1659482827030000,
data: { type: 'pear', colors: [ 'yellow', 'brown' ], quantity: 60 }
}
]
}
To query a database at a particular point in time, you can use the
At
function. At
adds a condition to a query which matches only
documents which were created at or before a specified timestamp.
ObjectV(data: Arr(ObjectV(ref: RefV(id = "1", collection = RefV(id = "fruit", collection = RefV(id = "collections"))),ts: LongV(1659484867110000),data: ObjectV(type: StringV(apple),colors: Arr(StringV(red), StringV(green)),quantity: LongV(15)))))
map[data:[map[data:map[colors:[red green] quantity:15 type:apple] ref:{1 0x1400011df20 0x1400011df20 <nil>} ts:1659630845970000]]]
{data: [{ref: ref(id = "1", collection = ref(id = "fruit", collection = ref(id = "collections"))), ts: 1659632352260000, data: {type: "apple", colors: ["red", "green"], quantity: 15}}]}
{
data: [
{
ref: Ref(Collection("fruit"), "1"),
ts: 1641578425510000,
data: { type: 'apple', colors: [ 'red', 'green' ], quantity: 15 }
}
]
}
{'data': [{'ref': Ref(id=1, collection=Ref(id=fruit, collection=Ref(id=collections))), 'ts': 1659635021120000, 'data': {'type': 'apple', 'colors': ['red', 'green'], 'quantity': 15}}]}
{
data: [
{
ref: Ref(Collection("fruit"), "1"),
ts: 1659482825620000,
data: { type: 'apple', colors: [ 'red', 'green' ], quantity: 15 }
}
]
}
Replace the string <$TIMESTAMP>
with the value for ts
from the
document creation result.
Any documents which have been removed from the database due to
either history_days or ttl expiration cannot be retrieved with
temporal queries.
|
Conclusion
Temporality offers developers a rich set of features for working with versioned documents and querying collections based on document timestamps. See the following resources for more information about temporality:
-
Temporality (blog post)
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!