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 |
---|
Delete a collection
To delete a collection, delete its schema using any of the following:
-
The Fauna CLI
-
The Fauna Dashboard
-
The Fauna Core HTTP API’s Schema endpoints
-
The FQL
collectionDef.delete()
method.
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 |
---|
Exact match search
// 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 |
---|
Range search
// 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 a document reference as a field value:
// References 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` document reference as
// a `category` field value.
category: produce
})
See Create a document relationship |
---|
Resolve document relationships
You can project a field that contains a document to dynamically resolve the document reference:
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,
// Resolves 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 Resolve document relationships with projection |
---|
Delete document relationships
To delete a document relationship, remove the field that contains the document reference. Removing the field does not delete the referenced document. For example:
// Updates a `Product` collection document.
Product.byId("111")?.update({
// Removes the `category` field, which contains a
// reference to a `Category` collection document.
// Removing the `category` field does not delete
// the `Category` document.
category: null
})
Dangling references
Deleting a document does not remove its inbound document references. Documents may contain references to Nulldocs — documents that don’t exist. These are called dangling references. For example:
// Gets a `Product` collection document.
// Use projection to return `name`, `description`, and `category` fields.
Product.byId("111") {
name,
description,
// The `category` field contains a reference to a `Category` collection document.
category
}
{
name: "cups",
description: "Translucent 9 Oz, 100 ct",
// If the referenced `Category` collection document doesn't exist,
// the projection returns a NullDoc.
category: Category("123") /* not found */
}
Perform a cascading delete
A cascading delete is an operation where deleting a document in one collection automatically deletes related documents in other collections.
Fauna doesn’t provide automatic cascading deletes for user-defined
collections. Instead, you can use an index and
set.forEach()
to iterate through a
document’s relationships.
In the following example, you’ll delete a Category
collection document and
any Product
documents that reference the category.
-
Define an index as part of a collection schema:
collection Product { ... category: Ref<Category> ... // Defines the `byCategory()` index. // Use the index to get `Product` collection // documents by `category` value. In this case, // `category` contains a reference to a `Category` collection document. index byCategory { terms [.category] } }
-
Use the index and
set.forEach()
to delete the category and any related products:// Gets a `Category` collection document. let category = Category.byId("333") // Gets `Product` collection documents that // contain the `Category` document in the `category` field. let products = Product.byCategory(category) // Deletes the `Category` collection document. category?.delete() // Deletes `Product` collection documents that // contain the `Category` document in the `category` field. products.forEach(.delete()) // Returns `null`
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() |
---|