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 Dashboard.
-
The Fauna CLI.
fauna schema push
command. -
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 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!