Quick start
Fauna is a serverless document-relational database you access through a cloud API.
In this tutorial, 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.
Create a database
To start, create a database in the Fauna Dashboard and populate it with demo data.
-
Go to the Fauna Dashboard and sign in.
You can sign up for a free account at https://dashboard.fauna.com/register.
-
Click Create Database.
-
Enter a database Name. For this tutorial, use
Demo
. -
Fill out the remaining fields as follows:
-
Select the Region Group nearest you.
-
Toggle Use demo data on.
-
Toggle Enable backups off.
-
-
Click Create.
Run an FQL query
You use FQL queries to read and write data in a Fauna database.
You send queries to Fauna using an HTTP API. The API lets you interact with Fauna using Fauna’s client drivers or any other client that sends HTTP requests.
You can also run FQL queries in the Dashboard Shell:
-
In the Dashboard’s left navigation, click Explorer.
-
Expand your region group and click the Demo database.
This opens the Dashboard Shell.
-
Paste the following FQL query into the shell:
Product.sortedByPriceLowToHigh() { name, description, price }
Don’t worry about the query syntax for now. We’ll cover that later in the tutorial.
-
Press Ctrl + Enter to run the query.
The query returns:
{ data: [ { name: "limes", description: "Conventional, 1 ct", price: 0.35 }, ... { name: "pinata", description: "Original Classic Donkey Pinata", price: 24.99 } ] }
Compose a query
You add data to Fauna as JSON objects called documents. The database stores documents in collections.
You can filter and fetch documents from a collection as a set, and iterate through each document.
You typically compose a query by calling one or more methods on a document, collection, or set using a TypeScript-like syntax. Expressions are evaluated sequentially from left to right.
For example, the following query calls the
all()
method
on the Product
collection.
// Get all documents from the `Product` collection
Product.all()
While useful for prototyping,
|
The query returns a set of Product
documents:
{
data: [
{
id: "394260846385037376",
coll: Product,
ts: Time("2099-04-04T18:28:13.250Z"),
name: "cups",
description: "Translucent 9 Oz, 100 ct",
price: 6.98,
...
},
...
{
id: "394260846402863168",
coll: Product,
ts: Time("2099-04-04T18:28:13.250Z"),
name: "pinata",
description: "Giant Taco Pinata",
price: 23.99,
...
}
]
}
Static typing
FQL is statically typed. Every expression has a data type that’s checked for correctness before evaluation.
For example, you can call
firstWhere()
on a collection, but not a document.
// Get the first product named "cups"
Product.firstWhere(.name == "cups")
Like |
Static typing helps catch errors early and more consistently, saving you time. You can also turn off type checking for any query.
Method chaining
Method chaining lets you use dot notation to call a method on the output of the previous method.
The following query calls
update()
on the
document returned by
firstWhere()
.
// Rename the "cups" product to "clear cups" if it exists
Product.firstWhere(.name == "cups")
?.update({ name: "clear cups" })
?.
safely calls
update()
only if
firstWhere()
returns a non-null value.
Write data
Each document has a string-encoded, 64-bit id
. This id
is unique for the
document within its collection.
Use create()
to create, or insert, a document in a collection. If wanted, you can specify
an id
for the document.
// Create a document with a specific `id`
Product.create({
id: "392886847463751746",
name: "limes",
description: "Organic, 1 ct",
price: 0.65
})
If you don’t specify an id
, Fauna auto-generates one. Once
assigned, the document id
is immutable and can’t be changed.
CRUD operations
FQL also supports methods for updating, replacing, and deleting documents.
The following queries use
byId()
to
fetch the document you created. The queries then call another method to modify
the document.
// Update a document
Product.byId("392886847463751746")
?.update({ price: 0.75 })
// Replace a document
// Product.byId("392886847463751746")
// ?.replace({
// name: "key limes",
// description: "Organic, 2 ct",
// price: 0.95
// })
// Delete a document
// Product.byId("392886847463751746")
// ?.delete()
Read data
Earlier queries used
byId()
to
fetch a single document. Other methods fetch a set of documents from a
collection.
Filter documents in collections
Use where()
to
filter documents from a collection.
// Get products named "limes"
Product.where(.name == "limes")
// Equivalent to:
// Product.all()
// .where(.name == "limes")
where()
supports several
comparison operators.
For example:
// Get products not named "limes"
Product.where(.name != "limes")
// Get products with a price greater than or equal to 20
// Product.where(.price >= 20)
Indexes
While useful for one-off queries, all()
and where()
aren’t performant on
large collections. These methods require a scan of each document in the
collection. This results in slower, more expensive queries as the collection
grows.
Instead, create Indexes for common data access patterns. An index stores, or covers, specific field values for quicker retrieval without scanning each document.
FQL and FSL
Fauna has two languages:
-
FQL is for creating queries that write or read data. If you’re familiar with SQL, you can think of FQL as Fauna’s data query language (DQL), data manipulation language (DML), and procedural language all in one.
-
Fauna Schema Language (FSL) is for defining and creating collections, indexes, security roles, and similar entities. FSL is Fauna’s data definition language (DDL).
Collection schemas
You define indexes in FSL as part of a
collection schema. You typically
store a collection schema as a .fsl
file in a schema directory of a project.
You can then push and pull the files from Fauna using the
Fauna CLI.
You can also manage collection schemas and other FSL entities using the Fauna Dashboard.
Index definitions
An index definition can include:
-
Terms: Fields for exact match searches
-
Values: Fields for sorting and range searches
For example, the Product
collection schema has definitions for the byName
and sortedByPriceLowToHigh
indexes:
collection Product {
...
index byName {
terms [.name]
values [desc(.quantity)]
}
...
index sortedByPriceLowToHigh {
values [.price, .name, .description]
}
}
Run queries with indexes
You call an index as a method on the collection. You must pass an argument for each term in the index definition. All indexes return a set.
// Exact match search
Product.byName("limes")
// Sort by values
// Product.sortedByPriceLowToHigh()
// Range search
// Product.sortedByPriceLowToHigh({ from: 20, to: 30 })
// Combine terms and values
// Product.byName("limes", { from: 50, to: 10 })
Projection
By default, queries that return sets or documents include every document field. Use projection to return only the specific fields you want. This creates smaller response payloads and decreases egress costs.
The following query returns only the name
, description
, and price
fields
for Product
documents.
// Get product names, descriptions, and prices
Product.sortedByPriceLowToHigh() {
name,
description,
price
}
Response:
{
data: [
{
name: "limes",
description: "Conventional, 1 ct",
price: 0.35
},
...
{
name: "pinata",
description: "Original Classic Donkey Pinata",
price: 24.99
}
]
}
Covered queries
If you use projection on an index’s covered fields, Fauna gets the field values from the index. This is a covered query.
If the projection contains an uncovered field, Fauna must retrieve the field values from the documents. This is an uncovered query.
// This is a covered query.
// `name`, `description`, and `prices` are `values`
// in the `sortedByPriceLowToHigh` index definition.
Product.sortedByPriceLowToHigh() {
name,
description,
price
}
// This is an uncovered query.
// `quantity` is not one of the `terms` or `values`
// in the `sortedByPriceLowToHigh` index definition.
Product.sortedByPriceLowToHigh() {
quantity,
name
}
Covered queries are typically faster and less expensive than uncovered queries, which require document scans. If you frequently run uncovered queries, consider adding the uncovered fields to the index definition.
Use projections to resolve references
In Fauna, you create relationships between documents by referencing one document in another. For example:
// Create a store
let newStore = Store.create({
id: "393607951810560064",
name: "Acme Supply"
})
// Create a product with a store reference
Product.create({
id: "393607951812657216",
name: "key limes",
description: "Organic, 3 ct",
price: 1.00,
store: newStore
})
The response includes the reference in the store
field. If you get
the document or a set without projection, the reference is unresolved.
{
id: "393607951812657216",
coll: Product,
...
store: Store("393607951810560064")
}
Use projection to resolve the reference and return the store
document.
This is similar to a join in SQL.
Product.byId("393607951812657216") {
name,
description,
store {
id,
name
}
}
Response:
{
name: "key limes",
description: "Organic, 3 ct",
store: {
id: "393607951810560064",
name: "Acme Supply"
}
}
Create an API key
Next, you’ll connect to Fauna using a client. To do this, you need an API key. Create a key in the Dashboard:
-
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 Admin or Server and enter an optional Key Name.
Admin and Server are built-in roles. Fauna also supports user-defined roles.
-
Click Save.
-
Copy the Secret Key. This is an API key for the Demo 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 Fauna API key. Fauna’s client drivers can access the key from this variable.export FAUNA_SECRET=<apiKey>
-
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 library is currently in beta.
Navigate to your .NET or C# project directory and add the Fauna package to your project. Include the Json.NET package to serialize query responses to JSON.
mkdir app cd app dotnet new console dotnet add package Fauna --prerelease dotnet add package Newtonsoft.Json
-
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:The application prints product data from the demo database.
-
Run the application:
go run app.go
node app.mjs
python app.py
dotnet run
The application prints the following:
[ { name: 'limes', description: 'Conventional, 1 ct', price: 0.35 }, ... { name: 'pinata', description: 'Original Classic Donkey Pinata', price: 24.99 } ]
[ {"name": "clear cups", "description": "Translucent 9 Oz, 100 ct", "price": 6.98}, ... {"name": "pinata", "description": "Giant Taco Pinata", "price": 23.99}, ]
{ "Data": [ { "description": "Conventional, 1 ct", "name": "limes", "price": 0.35 }, ... { "description": "Original Classic Donkey Pinata", "name": "pinata", "price": 24.99 } ], "After": "" }
{ "Data": [ { "name": "limes", "description": "Conventional, 1 ct", "price": 0.35 }, ... { "name": "pinata", "description": "Original Classic Donkey Pinata", "price": 24.99 } ], "After": null }
Next steps
Congratulations! You’ve created a database, run some queries, and integrated Fauna with an application.
To get more out of Fauna, try some of the following next steps:
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!