Check out v4 of the Fauna CLI

v4 of the Fauna CLI is now in beta.

The new version introduces enhancements to the developer experience, including an improved authentication workflow. To get started, check out the CLI v4 quick start.

CRUD and basic operations

This page contains examples of CRUD queries and other common database operations in Fauna Query Language (FQL) and Fauna Schema Language (FSL).

Collections

Create a collection

To create a collection, add an FSL collection schema to Fauna using a staged schema change.

// Defines the `Customer` collection.
collection Customer {
  // Field definitions.
  // Define the structure of the collection's documents.
  name: String
  email: String
  address: {
    street: String
    city: String
    state: String
    postalCode: String
    country: 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 {
  name: String
  email: String
  address: {
    street: String
    city: String
    state: String
    postalCode: String
    country: String
  }
  // Adds the `points` field. Accepts `int` or `null` values.
  // Accepting `null` means the field is not required.
  points: Int?
  // Adds the `typeConflicts` field as a catch-all field for
  // existing `points` values that aren't `Int` or `null`.
  typeConflicts: { *: Any }?
  *: Any

  migrations {
    // Adds the `typeConflicts` field.
    add .typeConflicts
    // Adds the `points` field.
    add .points
    // Nests non-conforming `points` 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 any of the following:

Deleting a collection deletes its documents and indexes.

Documents

Create a document

// Creates a `Customer` collection document.
Customer.create({
  name: "John Doe",
  email: "john.doe@example.com",
  address: {
    street: "123 Main St",
    city: "San Francisco",
    state: "CA",
    postalCode: "12345",
    country: "United States"
  }
})
Reference: collection.create()

Get a single document

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

Update a document

// Updates a `Customer` collection document.
Customer.byId("111")?.update({
  // Updates the existing `name` field value.
  name: "Jonathan Doe",
  // Adds new `points` field.
  points: 42
})
Reference: document.update()

Upsert a document

// Try to find an existing customer.
// If the customer doesn't exist, returns `null`.
let customer = Customer.byId("111")

// Customer data to upsert
let data = {
  name: "Alice Appleseed",
  email: "alice.appleseed@example.com",
  address: {
    street: "87856 Mendota Court",
    city: "Washington",
    state: "DC",
    postalCode: "20220",
    country: "US"
  }
}

// Create or update the customer
// based on existence.
if (customer == null) {
  Customer.create(data)
} else {
  customer!.update(data)
}

Remove a document field

// Updates a `Customer` collection document.
Customer.byId("111")?.update({
  // Removes the `points` field.
  points: null
})
Reference: document.update()

Replace a document

// Replaces a `Customer` collection document.
Customer.byId("111")?.replace({
  name: "Jane Doe",
  email: "jane.doe@example.com",
  address: {
    street: "87856 Mendota Court",
    city: "Washington",
    state: "DC",
    postalCode: "20220",
    country: "US"
  }
})
Reference: document.replace()

Delete a document

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

Bulk writes

Use set.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: {
    street: doc?.address?.street,
    city: doc?.address?.city,
    state: "District of Columbia",
    postalCode: doc?.address?.postalCode,
    country: doc?.address?.country,
  }
})) // `forEach()` returns `null`.

For more examples, see Bulk writes.

Reference: set.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 `name` and `email` field values.
    values [.name, .email]
  }
}
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 [.name, .email]
  }
}

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), then ...
// - `stock` (ascending).
Product.all().order(.price, .name, .description, .stock)

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, .stock]
  }
}

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), then ...
// - `stock` (ascending).
Product.sortedByPriceLowToHigh()
See Sort collection documents
// Runs an unindexed query.
// Get `Product` collection documents with a `price` between
// 10_00 and 100_00 (inclusive).
Product.where(.price >= 10_00 && .price <= 100_00)
  .order(.price, .name, .description, .stock)

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, .stock]
  }
}

Call the index in a query:

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

Projection

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

Paginate results

Fauna automatically paginates result Sets with 16 or more elements.

When a query returns paginated results, Fauna materializes a subset of the Set with an after pagination cursor:

// Uses the `Product` collection's `sortedByPriceLowToHigh()` index to
// return all `Product` collection documents.
// The collection contains more than 16 documents.
Product.sortedByPriceLowToHigh()
{
  // The result Set contains 16 elements.
  data: [
    {
      id: "555",
      coll: Product,
      ts: Time("2099-07-30T15:57:03.730Z"),
      name: "single lime",
      description: "Conventional, 1 ct",
      price: 35,
      stock: 1000,
      category: Category("789")
    },
    {
      id: "888",
      coll: Product,
      ts: Time("2099-07-30T15:57:03.730Z"),
      name: "cilantro",
      description: "Organic, 1 bunch",
      price: 149,
      stock: 100,
      category: Category("789")
    }
  ],
 // Use the `after` cursor to get the next page of results.
  after: "hdW..."
}

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

Set.paginate("hdW...")

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 `Category` collection document.
let produce = Category.byName("produce").first()

// Creates a `Product` collection document.
Product.create({
  name: "lemons",
  description: "Organic, 16 ct",
  price: 2_49,
  stock: 200,
  // Adds the previous `Category` collection document as
  // a `category` field value.
  category: produce
})
See Create a document relationship

Traverse document relationships

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

let produce = Category.byName("produce").first()

// Projects the `name`, `description`, `price`,
// and `category` fields.
Product.byCategory(produce) {
  name,
  description,
  price,
  category
}
{
  data: [
    {
      name: "avocados",
      description: "Conventional Hass, 4ct bag",
      price: 399,
      // Traverses the `Category` collection document in
      // the `category` field.
      category: {
        id: "789",
        coll: Category,
        ts: Time("2099-07-29T21:18:48.680Z"),
        products: "hdW...",
        name: "produce",
        description: "Fresh Produce"
      }
    },
    {
      name: "single lime",
      description: "Conventional, 1 ct",
      price: 35,
      category: {
        id: "789",
        coll: Category,
        ts: Time("2099-07-29T21:18:48.680Z"),
        products: "hdW...",
        name: "produce",
        description: "Fresh Produce"
      }
    },
    ...
  ]
}
See Traverse document relationships with projection

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: database.update()

Delete a child database

// Deletes the `childDB` child database.
Database.byName("childDB")?.delete()
Reference: database.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!