Temporality

Fauna documents are temporal. Create, update, and delete operations are assigned a transaction timestamp that maintains a document history.

With document history, you to query your database at a point in time. This facilitates event sourcing, reactive programming, and audit- and stream-oriented data architectures.

Document history

When a document is created or updated, Fauna stores a new version of the document with the current transaction timestamp. Fauna indexes also store the history of fields in the index terms or values definitions. The result is a record of the evolution of your database, updated as changes occur.

Fetch a document snapshot

You can use an at expression to run a temporal query. Temporal queries get a snapshot of one or more documents from a previous point in time.

For example, the following query retrieves a snapshot of a document from yesterday:

let yesterday = Time.now().subtract(1, "day")
at (yesterday) { Product.byName("avocados").first() }

Document or history removal

Temporal queries work as expected when document history exists. Note that document history increases the amount of storage required for your database, and significant amounts of history can affect the performance of your queries.

If temporality is less important than billing and performance, you should use one or more of the following features to remove document history or to remove documents and their history:

Document history removal

The history_days field defines the number of days of document history to maintain for all documents in the collection. After the number of days elapses, document history is removed, but the document is retained.

This feature is useful for documents that change frequently, and only the most recent versions are required. For example, a document that stores a rolling overage of some activity over the past month.

The default history_days value of zero is appropriate for a collection that stores counters because those are updated at a high rate. Counters that update multiple times per second can cause enough history to be retained to noticeably affect the performance of queries operating on the counter.

Setting history_days to null causes a collection to retain version history for each document indefinitely. The more frequently that documents are updated in a collection, the more that history consumes database storage. When an indexed field is frequently updated, the indexes retain the history of indexed fields also, which can increase the latency for queries on that index over time. Be aware of how your history_days choice affects your storage costs and query latency, and avoid unnecessary history retention.

Setting history_days to zero retains only the current version of each document in a collection, and no history is retained.

Updating history_days has the following behavior. If history_days becomes smaller, such as changing the value from 10 days to zero days, history is truncated as of the time of the collection document update minus the new history_days value. History before the new history_days setting is inaccessible.

If history_days becomes larger, such as changing the value from zero to 30 days, history begins accumulating as of the time of the collection document update. After history_days expires, history before the time of the update to the collection becomes inaccessible.

Document removal

The ttl document field specifies the document time-to-live. When the ttl timestamp is passed, the document is removed, but its history continues to exist until the collection history_days has elapsed.

This feature can be useful for documents that must exist for short intervals, and you want to avoid executing maintenance queries to remove the documents.

This is particularly useful for intermediate documents involved in gathering report data. These documents must be retained during complex report preparation. After the report is generated, the documents are removed.

This feature should be used with caution because documents with ttl set might be removed. As such, the default ttl is undefined, which means the document history is retained indefinitely.

The ttl field controls the following behavior:

  • Queries using temporality return an error if the effective query timestamp is older than a collection history_days value.

  • Indexes don’t report document events older than the history_days value in the source collections.

Set a default ttl

A collection schema’s ttl_days field defines the default retention period, in days, for documents in the collection. When ttl_days is set, new documents in the collections are assigned a ttl value based on ttl_days and the document’s last write.

Enable or disable ttl writes

A collection schema’s document_ttls field controls whether you can write to the ttl field of the collection’s documents.

document_ttls does not affect the ttl of existing documents. Fauna will continue to delete documents based on their ttl, even if document_ttls is false.

document_ttls also does not affect the collection schema’s ttl_days field. If configured, ttl_days will continue to set a ttl on document writes, even if document_ttls is false.

If the collection schema contains field definitions, document_ttls defaults to false. Otherwise, document_ttls defaults to true.

Set a ttl for existing collection documents

You can update a collection’s schema to set or change its ttl_days value.

collection Product {
  ...
  // Explicitly set `document_ttls` to `true`
  document_ttls true
  // Set default document `ttl` to timestamp + 365 days
  ttl_days 365
  ...
}

Changing ttl_days on an existing collection only affects:

  • New documents

  • Documents changed after ttl_days is set

It does not change the ttl of existing documents.

To set the ttl for a large set of existing documents, you can iterate through the collection instead. You’ll likely need to use paginate() to perform the update over several transactions.

// First transaction
let page = Product
  .all()
  .where(.ttl == null)
  .paginate()

// Subsequent transactions
// let page = Set.paginate("hdWDxoq...")

let data = page.data

data.forEach(document => document.update({
  // Set ttl as document timestamp + 365 days
  ttl: document.ts.add(365, "days")
}))

page {
  after
}

To set the ttl for a small set of existing documents, you can create a new collection with your desired ttl_days value. Then copy documents you want to update to the collection.

// Get retained documents from the ProductOld collection
let docsToCopy = ProductOld
  .all()
  .where(.ttl == null)
  .toArray()
  .map(document => Object.assign({ }, document.data))

// Adds the documents to the ProductNew collection
docsToCopy.map(data => ProductNew.create(data))

See also

See the at expression reference documentation for how to query your database at a point in time.

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!