Quick start
Fauna is a distributed document-relational database. You can use Fauna databases to build secure, scalable multi-tenant applications.
In this quick start guide, you’ll:
-
Create a Fauna database with demo data.
-
Run Fauna Query Language (FQL) queries to read and write data.
-
Build an application that integrates with Fauna using a client driver.
Prefer to learn using a sample application? Check out the driver sample apps on GitHub: |
Create a database
Create a database with demo data:
-
Log in to the Fauna Dashboard. You can sign up for a free account at https://dashboard.fauna.com/register.
-
Create a database. When creating the database, enable demo data.
-
Navigate to the database in the Dashboard.
Read data
You use FQL queries to read data in a Fauna database. You can run FQL queries in the Dashboard Shell.
Get all collection documents
Fauna stores data as JSON-like documents in collections.
You can filter and fetch documents from a collection as a set, and iterate through each document.
Run the following FQL query to get all documents in the demo data’s Customer
collection. The query calls the
collection.all()
method
on the Customer
collection:
// Calls `all()` on the `Customer` collection.
Customer.all()
The query returns a set of Customer
collection documents. Each document has a
64-bit id
that’s unique to the document within the collection.
{
data: [
{
// Document ID, generated on write.
id: "111",
coll: Customer,
ts: Time("2099-07-29T21:46:41.440Z"),
cart: Order("<ORDER_DOCUMENT_ID>"),
orders: "hdW...",
name: "Alice Appleseed",
email: "alice.appleseed@example.com",
address: {
street: "87856 Mendota Court",
city: "Washington",
state: "District of Columbia",
postalCode: "20220",
country: "US"
}
},
...
]
}
Exact match search
For one-off queries, use
collection.where()
to
filter documents using a
predicate:
// 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. An index stores, or covers, specific document field values for quick retrieval.
You define indexes in an FSL collection schema. The
demo data includes a schema for the Customer
collection:
collection Customer {
...
// Unique constraint.
// Ensures a field value or combination of field values
// is unique for each document in the collection.
unique [.email]
// Definition for the `byEmail()` index.
// Use indexes to filter and sort documents
// in a performant way.
index byEmail {
// `terms` are document fields for exact match searches.
// In this example, you get `Customer` collection documents
// by their unique `email` field value.
terms [.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")
{
data: [
{
id: "111",
coll: Customer,
ts: Time("2099-07-29T21:46:41.440Z"),
cart: Order("<ORDER_DOCUMENT_ID>"),
orders: "hdW...",
name: "Alice Appleseed",
email: "alice.appleseed@example.com",
address: {
street: "87856 Mendota Court",
city: "Washington",
state: "District of Columbia",
postalCode: "20220",
country: "US"
}
}
]
}
Sort data
You can use method chaining to call a method on the output of another method. Expressions are evaluated sequentially from left to right.
The following query calls
set.order()
on the output of
collection.all()
:
// 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.
The demo data includes a schema for the Product
collection:
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()
Range search
For one-off queries, use
Collection.where()
to
filter 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:
// Get `Product` collection documents with a `price` between
// 10_00 and 100_00 (inclusive).
Product.sortedByPriceLowToHigh({ from: 10_00, to: 100_00 })
Project results
Projection lets you return only the specific fields you want from queries. Use projection to create smaller response payloads and decrease egress costs.
// Get only product names, descriptions, and prices
Product.sortedByPriceLowToHigh() {
name,
description,
price
}
{
data: [
{
name: "single lime",
description: "Conventional, 1 ct",
price: 35
},
...
{
name: "donkey pinata",
description: "Original Classic Donkey Pinata",
price: 2499
}
]
}
Paginate results
Fauna automatically paginates sets with 16 or more
elements. Use set.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 result set contains two elements or fewer.
data: [
{
name: "single lime",
description: "Conventional, 1 ct",
price: 35
},
{
name: "cilantro",
description: "Organic, 1 bunch",
price: 149
}
],
// 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:
Write data
You also use FQL queries to write data to a Fauna database.
Create a document
Use collection.create()
to create, or insert, a document in a collection:
// Calls `create()` on the `Customer` collection.
// Creates a `Customer` collection document.
Customer.create({
name: "John Doe",
email: "jdoe@example.com",
address: {
street: "87856 Mendota Court",
city: "Washington",
state: "District of Columbia",
postalCode: "20220",
country: "US"
}
})
If wanted, you can also provide a document id
. If you don’t provide an ID,
Fauna auto-generates one. Once assigned, the document ID is immutable and
can’t be changed.
Customer.create({
id: "12345",
name: "Jacob Doe",
email: "jacob.doe@example.com",
address: {
street: "87856 Mendota Court",
city: "Washington",
state: "District of Columbia",
postalCode: "20220",
country: "US"
}
})
Update a document
Use document.update()
to update a document:
// Declares a `customer` variable.
// Uses the `Customer` collection's `byEmail()` index to
// get `Customer` collection documents by `email` field value.
// In the `Customer` collection, `email` field values are unique
// so return the `first()` (and only) document.
let customer = Customer.byEmail("jdoe@example.com").first()
// Calls `update()` on the `Customer` collection document.
// `?.` safely calls `update()` only if `customer` contains
// a non-null value.
customer?.update({
// Updates the existing `name` field value.
name: "Jonathan Doe"
})
Replace a document
Use document.replace()
to replace a document:
let customer = Customer.byEmail("jdoe@example.com").first()
// Calls `replace()` on the `Customer` collection document.
customer?.replace({
name: "Jane Doe",
email: "jdoe@example.com",
address: {
street: "87856 Mendota Court",
city: "Washington",
state: "District of Columbia",
postalCode: "20220",
country: "US"
}
})
Delete a document
Use document.delete()
to delete a document:
let customer = Customer.byEmail("jdoe@example.com").first()
// Calls `delete()` on the `Customer` collection document.
customer?.delete()
The query returns a NullDoc, which indicates the document no longer exists:
Customer("<DOCUMENT_ID>") /* deleted */
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.
Document relationships
A document relationship establishes associations between documents. Fauna supports one-to-one, one-to-many, and many-to-many relationships between documents in different collections.
Create a relationship between documents
To create a document relationship, include the document as a field value:
// Uses the `Category` collection's `byName()`
// index to get the first category named `produce`.
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
})
Traverse document relationships
You can project a field that contains a document to dynamically traverse the document relationship:
// Get product names, category, and prices
Product.sortedByCategory() {
name,
category,
price
}
{
data: [
{
name: "cups",
// Traverses the `Category` collection document in
// the `category` field.
category: {
id: "<CATEGORY_DOCUMENT_ID>",
coll: Category,
ts: Time("2099-07-30T12:35:24.630Z"),
products: "hdW...",
name: "party",
description: "Party Supplies"
},
price: 698
},
{
name: "donkey pinata",
category: {
id: "<CATEGORY_DOCUMENT_ID>",
coll: Category,
ts: Time("2099-07-30T12:35:24.630Z"),
products: "hdW...",
name: "party",
description: "Party Supplies"
},
price: 2499
},
...
]
}
Create a child database for multi-tenancy
You can use FQL to programmatically create
child databases. Child databases are
represented as Database
collection documents in the parent database:
// Create a child database named `childDB`
Database.create({
name: "childDB",
typechecked: true,
priority: 10
})
For multi-tenant applications, you can create a child database for each tenant. Each database is isolated from its peers and becomes available immediately upon creation.
You can populate and access the database’s data using a secret that’s scoped to the database.
You can also use a scoped key to access a child database from its parent and manage its data.
Create a secret
To connect to Fauna using a client you need a secret to authenticate with Fauna. Each secret is scoped to a specific database.
Fauna supports several secret types. For the quick start, create a key, which is a type of secret:
-
In the upper left pane of Dashboard’s Explorer page, click the demo database, and click the Keys tab.
-
Click Create Key.
-
Choose a Role of Server.
-
Click Save.
-
Copy the Key Secret. The secret is scoped to the database.
Build an application
Next, create a basic application that integrates with Fauna using a Fauna client driver.
A client driver sends FQL queries and receives responses using your preferred programming language. The client deserializes query responses into the language’s corresponding data types.
-
Set the
FAUNA_SECRET
environment variable to your key’s secret. Fauna’s client drivers can access the secret from this variable.export FAUNA_SECRET=<KEY_SECRET>
-
Create a directory for the app and install the driver.
mkdir app cd app go mod init app go get github.com/fauna/fauna-go
mkdir app cd app npm install fauna
mkdir app cd app pip install fauna
The C# client driver is currently in beta.
Navigate to your .NET or C# project directory and add the Fauna package to your project.
mkdir app cd app dotnet new console dotnet add package Fauna --prerelease
The JVM client driver is currently in beta.
For the quick start, install the driver using Gradle.
Navigate to your Java project directory and create a project.
mkdir app cd app gradle init --type java-application
When prompted, enter:
-
Enter target Java version: 17
-
Project name: app
-
Select application structure: 1 (Single application project)
-
Select build script DSL: 2 (Groovy)
-
Select test framework: 1 (JUnit 4)
-
Generate build using new APIs…: no
Edit
app/build.gradle
and add the following dependency:dependencies { ... implementation "com.fauna:fauna-jvm:0.2.0-B1" ... }
Save
app/build.gradle
. -
-
Create an
app.go
file and add the following code:Create an
app.mjs
file and add the following code:Create an
app.py
file and add the following code:Edit the
Program.cs
file and replace the code with the following:Edit the
app/src/main/java/org/example/App.java
file and replace the code with the following:The application prints product data from the demo database.
-
Run the application:
go run app.go
node app.mjs
python app.py
dotnet run
./gradlew run
The application prints the following:
[ { name: 'single lime', description: 'Conventional, 1 ct', price: 0.35 }, { name: 'cilantro', description: 'Organic, 1 bunch', price: 1.49 } ]
[ { "name": "single lime", "description": "Conventional, 1 ct", "price": 0.35 }, { "name": "cilantro", "description": "Organic, 1 bunch", "price": 1.49 } ]
[ { name: 'single lime', description: 'Conventional, 1 ct', price: 0.35 }, { name: 'cilantro', description: 'Organic, 1 bunch', price: 1.49 } ]
[ { "name": "single lime", "description": "Conventional, 1 ct", "price": 0.35 }, { "name": "cilantro", "description": "Organic, 1 bunch", "price": 1.49 } ]
Name: single lime Description: Conventional, 1 ct Price: 0.35 -------- Name: cilantro Description: Organic, 1 bunch Price: 1.49 -------- After: hdWC...
Next steps
Congratulations! You’ve created a database, run some queries, and integrated Fauna with an application.
As a next step, try one of the following:
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!