Fauna cheat sheet

This cheat sheet contains examples of common database operations in Fauna Query Language (FQL) and Fauna Schema Language (FSL). For additional context, check out the Overview and Quick start.

Collections

Create a collection

To create a collection, add an FSL collection schema in the Fauna Dashboard or upload the schema using the Fauna CLI:

// Defines the `Customer` collection.
collection Customer {
  // Field definitions.
  // Define the structure of the collection's documents.
  email: String
  firstName: String?
  lastName: String?
  status: String?
  address: {
    street: String?,
    city: String?,
    state: String?,
    zipCode: String?,
  }?
  telephone: String?
  creditCard: {
    network: "Visa" | "MasterCard" | "American Express"?,
    number: String?,
  }?

  // Wildcard constraint.
  // Allows arbitrary ad hoc fields of any type.
  *: Any
  // If a collection schema has no field definitions
  // and no wildcard constraint, it has an implicit
  // wildcard constraint of `*: Any`.
}
See Schema

Edit a collection

Update a collection’s document type using a zero-downtime schema migration:

collection Customer {
  email: String
  firstName: String?
  lastName: String?
  status: String?
  address: {
    street: String?,
    city: String?,
    state: String?,
    zipCode: String?,
  }?
  telephone: String?
  creditCard: {
    network: "Visa" | "MasterCard" | "American Express"?,
    number: String?,
  }?
  // Adds the `age` field. Accepts `int` or `null` values.
  // Accepting `null` means the field is not required.
  age: Int?
  // Adds the `typeConflicts` field as a catch-all field for
  // existing `age` values that aren't `Int` or `null`.
  typeConflicts: { *: Any }?
  *: Any
  migrations {
    // Adds the `typeConflicts` field.
    add .typeConflicts
    // Adds the `age` field.
    add .age
    // Nests non-conforming `age` and `typeConflicts`
    // field values in the `typeConflicts` catch-all field.
    move_conflicts .typeConflicts
  }
}
See Schema migrations

View collections

Collection.all()
Reference: Collection.all()

Delete a collection

To delete a collection, delete its schema using the Fauna Dashboard or Fauna CLI. Deleting a collection deletes its documents and indexes.

Documents

Create a document

// Creates a `Customer` collection document.
Customer.create({
  firstName: "John",
  lastName: "Doe",
  email: "jdoe@example.com"
})
Reference: create()

Get a single document

// Gets a `Customer` collection document.
// Replace `<DOCUMENT_ID>` with a document `id`.
Customer.byId("<DOCUMENT_ID>")
Reference: byId()

Update a document

// Updates a `Customer` collection document.
Customer.byId("<DOCUMENT_ID>")?.update({
  // Updates the existing `firstName` field value.
  firstName: "Jonathan",
  // Adds new `age` field.
  age: 42
})
Reference: update()

Remove a document field

// Updates a `Customer` collection document.
Customer.byId("<DOCUMENT_ID>")?.update({
  // Removes the `age` field.
  age: null
})
Reference: update()

Replace a document

// Replaces a `Customer` collection document.
Customer.byId("<DOCUMENT_ID>")?.replace({
  firstName: "Jane",
  lastName: "Doe",
  email: "jane.doe@example.com"
})
Reference: replace()

Delete a document

// Deletes a `Customer` collection document.
Customer.byId("<DOCUMENT_ID>")?.delete()
Reference: delete()

Bulk writes

Use forEach() to iteratively update each document in a set:

// Get a set of `Customer` collection documents with an
// `address` in the `state` of `DC`.
let customers = Customer.where(.address?.state == "DC")
// Use `forEach()` to update each document in the previous set.
customers.forEach(doc => doc.update({
  address: {
    state: "District of Columbia"
  }
})) // `forEach()` returns `null`.

For more examples, see Bulk writes.

Reference: forEach()

Indexes and reads

Create an index

You define indexes in FSL as part of a collection schema:

collection Customer {
  ...
  index byEmail {
    // `terms` are document fields for exact match searches.
    // In this example, you get `Customer` collection documents
    // by their `email` field value.
    terms [.email]
    // `values` are document fields for sorting and range searches.
    // In this example, you sort or filter index results by their
    // descending `firstName` and `lastName` field values.
    values [.firstName, .lastName]
  }
}
See Define an index
// Runs an unindexed query.
Customer.where(.email == "alice.appleseed@example.com")

For better performance on large datasets, use an index with a term to run an exact match search.

Define the index in the collection schema:

collection Customer {
  ...
  // Defines the `byEmail()` index for the `Customer`
  // collection.
  index byEmail {
    // Includes the `email` field as an index term.
    terms [.email]
    values [.firstName, .lastName]
  }
}

You call an index as a method on its collection:

// Uses the `Customer` collection's `byEmail()` index
// to run an exact match search on an `email` field value.
Customer.byEmail("alice.appleseed@example.com")
See Run an exact match search

Sort collection documents

// Runs an unindexed query.
// Sorts `Product` collection documents by:
// - `price` (ascending), then ...
// - `name` (ascending), then ...
// - `description` (ascending).
Product.all().order(.price, .name, .description)

For better performance on large datasets, use an index with values to sort collection documents.

Define the index in the collection schema:

collection Product {
  ...
  // Defines the `sortedByPriceLowToHigh()` index.
  index sortedByPriceLowToHigh {
    // `values` are document fields for sorting and range searches.
    values [.price, .name, .description]
  }
}

Call the index in a query:

// Uses the `Product` collection's `sortedByPriceLowToHigh()` index
// to sort `Product` collection documents by:
// - `price` (ascending), then ...
// - `name` (ascending), then ...
// - `description` (ascending).
Product.sortedByPriceLowToHigh()
See Sort collection documents
// Runs an unindexed query.
// Get `Product` collection documents with a `price` between
// 10 and 100 (inclusive).
Product.where(.price >= 10 && .price <= 100)
  .order(.price, .name, .description)

For better performance on large datasets, use an index with values to run range searches on collection documents,

Define the index in the collection schema:

collection Product {
  ...
  // Defines the `sortedByPriceLowToHigh()` index.
  index sortedByPriceLowToHigh {
    // `values` are document fields for sorting and range searches.
    values [.price, .name, .description]
  }
}

Call the index in a query:

// Get `Product` collection documents with a `price` between
// 10  and 100 (inclusive).
Product.sortedByPriceLowToHigh({ from: 10, to: 100 })
See Run a range search

Projection

// Projects the `name`, `description`, and `price` fields.
Product.sortedByPriceLowToHigh() {
  name,
  description,
  price
}
{
  data: [
    {
      name: "limes",
      description: "Conventional, 1 ct",
      price: 0.35
    },
    {
      name: "cilantro",
      description: "Organic, 1 bunch",
      price: 1.49
    },
    ...
  ]
}
Reference: Projection and field aliasing

Paginate results

Fauna automatically paginates sets with 16 or more elements. Use pageSize() to change the maximum number of elements per page:

// Calls `pageSize()` with a size of `2`.
Product.sortedByPriceLowToHigh().pageSize(2) {
  name,
  description,
  price
}

If a set is paginated and a subsequent page is available, the result includes an after cursor:

{
  // The results contain two elements or fewer.
  data: [
    {
      name: "limes",
      description: "Conventional, 1 ct",
      price: 0.35
    },
    {
      name: "cilantro",
      description: "Organic, 1 bunch",
      price: 1.49
    }
  ],
   // Use the `after` cursor to get the next page of results.
  after: "hdWCxmd..."
}

To get the next page of results, pass the after cursor to Set.paginate():

Set.paginate("hdWCxmd...")

The Fauna client drivers also include methods for automatically iterating through pages. See:

Document relationships

Create a document relationship

To create a document relationship, include the document as a field value:

// Gets a `Store` collection document.
let store = Store.byId("<DOCUMENT_ID>")

// Creates a `Product` collection document.
Product.create({
  name: "limes",
  description: "Organic, 2 ct",
  price: 1.98,
  quantity: 70,
  // Adds the previous `Store` collection document as
  // a `store` field value.
  store: store,
  backorderLimit: 5,
  backordered: false
})
See Create a document relationship

Traverse document relationships

You can project a field that contains a document to dynamically traverse the document relationship:

// Projects the `name`, `description`, `price`, and `store` fields.
Product.sortedByPriceLowToHigh() {
  name,
  description,
  price,
  store
}
{
  data: [
    {
      name: "limes",
      description: "Conventional, 1 ct",
      price: 0.35,
      // Traverses the `Store` collection document in
      // the `store` field.
      store: {
        id: "402336425534554189",
        coll: Store,
        ts: Time("2099-07-02T21:46:05.720Z"),
        name: "DC Fruits",
        address: {
          street: "13 Pierstorff Drive",
          city: "Washington",
          state: "DC",
          zipCode: "20220"
        }
      }
    },
    {
      name: "cilantro",
      description: "Organic, 1 bunch",
      price: 1.49,
      store: {
        id: "402336425534554189",
        coll: Store,
        ts: Time("2099-07-02T21:46:05.720Z"),
        name: "DC Fruits",
        address: {
          street: "13 Pierstorff Drive",
          city: "Washington",
          state: "DC",
          zipCode: "20220"
        }
      }
    },
    ...
  ]
}
See Traverse document relationships with projection

Event Streaming

Track changes to a collection

// Track changes to `Product` collection documents.
Product.all().toStream()
Reference: Collection streams

Track changes to an index

// Track changes to the set of documents
//  returned by the `byCategory()` index call.
Product.byCategory('sports').toStream()
Reference: Index streams

Track changes to a single document

// Track changes on a single `Product` collection document.
let product = Product.byId("<DOCUMENT_ID>")!
Set.single(product).toStream()
Reference: Document streams

Track changes on specific fields

// Only track changes to the `category` and `name` fields
// of the set of documents returned by the `byCategory()`
// index call.
Product.byCategory('sports').changesOn(.category, .name)
Reference: Event Streaming reference

Child databases

Create a child database

// Creates the `childDB` child database.
Database.create({
  name: "childDB",
  // Enables typechecking for the database.
  typechecked: true
})
Reference: Database.create()

Get a child database

// Gets the `childDB` child database.
Database.byName("childDB")
Reference: Database.byName()

Update a child database

// Updates the `childDB` child database's
// `typechecked` field.
Database.byName("childDB")?.update({typechecked: false})
Reference: update()

Delete a child database

// Deletes the `childDB` child database.
Database.byName("childDB")?.delete()
Reference: delete()

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!