FaunaDB: An Introduction


FaunaDB is one of the most popular upcoming databases on the cloud. It provides amazing flexibility and scalability.

It can be used as an OLTP database with distributed ACID transactions, or as a document database or a simple Key-Value based NoSQL. It includes support for enterprise features like configurable data retention and hierarchal multi-tenancy.

Moreover, FaunaDB does not bind you to the cloud. It is available as a managed cloud service or as a downloadable JAR, machine image, or container - that you can run on premise.

FaunaDB Features


FaunaDB provides extreme flexibility, allowing you to tweak as per your requirements. We can use it as a traditional relational database, as a key-value, document based, or graph database. We can enforce a schema on the data, or just let it loose.

We can run it on the cloud, as a serverless DB, with a generous free tier. Or we can also use it on premise, as an embedded DB, right inside our application. Ofcourse, it also provides for the intermediates like machine image or docker image.

All this comes with very high performance and ACID transactions. I guess that is all that any architect would want for an application.

FaunaDB Console


To start with, let us get a feel of the DB on the cloud. Easiest way is to visit the web console. FaunaDB does provide an elegant command shell for the cloud DB, but let us start with the web console.

Visit their website on https://fauna.com/ and Sign up. (Top right corner). There are different alternatives to signup. You can use the Github or Netfly account. Or just signup using your Email ID. After entering the basics, you are all set to build your application.

The dashboard looks like this

Create Database


Quite intuitive, you start with clicking New Database. Provide the DB name, and you are done. You have a new DB instance for your application. If you just want to get a feel of it, you can choose the option to fill the DB with dummy data. Or you can create your own data.

With that, you have a clean database instance.

Create Collection


Ofcourse, the next step is to create a collection. FaunaDB offers some choices when we create a new collection.

The create collection page looks like this:

Along with the collection name, we have two options. The History Date and the TTL (Time To Live) for each record. History is the number of days a the history of documents is retained (for possible undo). If we clear this field, the history is retained forever. Naturally, the history data is also a data that is charged on the cloud. So one must be careful while choosing this number

The TTL defines the number of days an untouched document stays in the collection - after the last write. It is quite helpful to set a reasonable value to TTL, as it can help reduce costs.

And finally, we hit save and the new collection is created. It presents a good UI to add new documents to the collection.

Create Document


Clicking that button shows us a text box where we can type in the JSON for the new document that we want to add to our collection.

The console also provides several other options for creating index, custom functions, adding a GraphQL schema and also for creating security keys for accessing the database.

If you are bored of the UI, the console provides a link for opening the Shell. Here, we can type in the required commands and get things through. In fact, FaunaDB also allows us to open a shell on our local terminal, that can interact with the DB. Let us now have a look at that.

Fauna Shell


Anyone serious about building real world applications should drop the web console and get back to the black screen. That is the true way to develop. FaunaDB provides for a very good CLI and a NodeJS based shell for communicating with the application on the cloud.

Let us start with the installations. If you are reading this blog, I am sure you know how to install NodeJS and NPM (if it is not already installed). So let us start beyond that point. We have to install the fauna shell using the npm.

npm install -g fauna-shell

There you go. Npm gathers all that you need to run the fauna shell and sets it up.

Next, we log into the fauna cloud account that account that we created above.

fauna cloud-login

This asks for the email/password that we used to signup. It has an option to login with a key (we will check that later).

Create Database


As we did from the console, the first step is to create the new database.

fauna create-database my-db

This shows some logs about creating the DB and then confirms the successful creation.

Once the database is created, we open the fauna shell for the given database

fauna shell my-db

This shows the below output and then opens the fauna-shell

Starting shell for database my-db
Connected to https://db.fauna.com
Type Ctrl+D or .exit to exit the shell
my-db>

Create Collection


Now, we are ready to play with data. The next step is to create the collection.

my-db> CreateCollection({name:"blog-posts"})

This creates a new collection. The creation is confirmed by the shell as

{ ref: Collection("blog-posts"),
  ts: 1594633187440000,
  history_days: 30,
  name: 'blog-posts' }

The ts: 1594633187440000 is the timestamp for this transaction and will be different when you do it.

Create Index


We created a collection that would hold all my blog posts. The collection has to be indexed - to enable querying. A natural candidate for the index is the blog title. Let's create that index here.

my-db> CreateIndex({name: "posts_by_title",
... source: Collection("blog-posts"),
... terms: [{field: ["data", "title"]}]})

The fauna shell confirms creation of the index by this log:

{ ref: Index("posts_by_title"),
  ts: 1594633307405000,
  active: true,
  serialized: true,
  name: 'posts_by_title',
  source: Collection("blog-posts"),
  terms: [ { field: [ 'data', 'title' ] } ],
  partitions: 1 }

Create Document


Now that we have a collection and the index ready, we start with adding data to it. This is how we do it.

my-db> Create(Collection("blog-posts"),
... {data: {title: "FaunaDB: An Introduction",
..... content: "FaunaDB is a wonderful Database. You must use it in your application"}})

The fauna shell confirms it with something like this.

{ ref: Ref(Collection("blog-posts"), "270925464408687111"),
  ts: 1594633507130000,
  data:
   { title: 'FaunaDB: An Introduction',
     content:
      'FaunaDB is a wonderful Database. You must use it in your application' } }

It is wasteful to type each record one by one. You might say the web console was better. The fauna shell provides us interesting ways of adding multiple records at once.

my-db> Map([{title: "Title 1", content: "Content 1"},
...             {title: "Title 2", content: "Content 2"},
...             {title: "Title 3", content: "Content 3"}],
...     Lambda("post", Create( Collection("blog-posts"), {data: Var("post")})))

This is confirmed by the log below.

[ { ref: Ref(Collection("blog-posts"), "270925725483140613"),
    ts: 1594633756110000,
    data: { title: 'Title 1', content: 'Content 1' } },
  { ref: Ref(Collection("blog-posts"), "270925725483139589"),
    ts: 1594633756110000,
    data: { title: 'Title 2', content: 'Content 2' } },
  { ref: Ref(Collection("blog-posts"), "270925725483141637"),
    ts: 1594633756110000,
    data: { title: 'Title 3', content: 'Content 3' } } ]

Here, we added three documents at once. Note that the list of three documents that we feed into the Map need not be typed here. The list can come out of any external source. There! Now, we can see the power of this shell.

Query Documents


Now, let us try to fetch records from the collection. There are two ways to query this data. Using the id, and using the index.

Note in the above create operations, we got a number - 270925464408687111 - in the confirmation, This can be used to query the record.

my-db> Get(Ref(Collection("blog-posts"), "270925725483139589"))

This returns the record we just inserted.

{ ref: Ref(Collection("blog-posts"), "270925725483139589"),
  ts: 1594633756110000,
  data: { title: 'Title 2', content: 'Content 2' } }

Ofcourse, this is a boring way to query the data. Why did we make the index? Let's use that index to query the required record.

We can query the same record using the index on title that we created above.

my-db> Get(Match(Index("posts_by_title"), "Title 2"))

It returns the same record.

{ ref: Ref(Collection("blog-posts"), "270925725483139589"),
  ts: 1594633756110000,
  data: { title: 'Title 2', content: 'Content 2' } }

References


That was just a glimpse of what we can do with the web console and shell. Fauna DB has a very good documentation. You can check out the Cookbook on their website for a good collection of code snippets for various use cases.

If you like videos more than text, here is a very good video on YouTube - that gives a good overview of Building Serverless Apps using FaunaDB