Tutorials > First steps with FaunaDB on Ubuntu 20.04

First steps with FaunaDB on Ubuntu 20.04

Published on: 24 March 2021

Database Development Ubuntu

Introduction

FaunaDB is a serverless and globally distributed ‘cloud as a service’ database. FaunaDB saves entities as documents of collections and can be used on serverless applications.

In this guide, you will be explained the first steps of the FaunaDB database, following its installation on an Ubuntu 20.04 server. You will also see some examples of the FaunaDB shell query language, as well as the creation of a song collection to be saved in the database as a use case.

Installing the Fauna shell

After creating an account through the FaunaDB registration procedure, install Shell Fauna on your machine.

l Now, connect your server via an SSH connection. If you haven't done so yet, following our guide is recommended to  connect securely with the SSH protocol. In case of a local server, go to the next step and open your server terminal.

To install Fauna on your server, use the npm command :

$ npm install -g fauna-shell

Logging into the FaunaDB account

The first step, after having opened the FaunaDB shell, is to proceed with the authentication in your Fauna account.

To do so, enter the following command in the shell:

$ fauna cloud-login

At this point, you will be requested to enter your login credentials. Inserted for the first time, the Shell will store them in a configuration file at $ HOME /.fauna-shell.

Creating a new database with Fauna

Depending on the use you choose, different databases can be created.

As in other database managers, all you need is a simple command within the shell, which, in this case, is as follows:

$ fauna create-database my_database

Note: in the example, ’my_database’ is the name of your choice for the DB created, but any other name can obviously be assigned.

Using FaunaDB and building the first objects

First of all, to choose which database to use, use the command:

$ fauna shell my_database

If the database was created successfully, a confirmation prompt should be returned.

Once in the shell, start by creating your first collection:

my_database> CreateCollection({ name: "songs" })

As in the example, let's imagine building a collection of songs to be saved in the database.

After the command, the shell will return information, called metadata, about the newly created collection.

Another step is to provide an index to easily find the songs saved in your DB by title:

my_database> CreateIndex({
 name: "songs_for_title",
 source: Collection("songs")
 terms: [{ field: ["data", "title"] }]
})

Manipulating the data

Adding data to the database

Once the scheme has been created, proceed to create the first document of your collection:

my_database> Create(
Collection("songs"),
{data: { title: "Luna" } }
)

The output that should be returned is a response on the newly posted document:

{ ref: Ref(Collection("songs"), "207089183860195845"),
 ts: 1533754485757944,
 data: { titolo: "Luna" } }

In case you need to insert more songs, use the Map function:

my_database> Map(
 [
 "Luna",
 "I giardini di marzo",
 "Rebel Rebel"
 ],
 Lambda("song_title",
 Create(
 Collection("songs"), { data: { titolo: Var("titolo_brano") } }
 )
 )
)

In the example:

  • Map is an array of songs that you want to register in the database;
  • Lambda is an anonymous function that will accept the "title_track" parameter and reuse it as the value of the title field in the newly inserted document.

At the end, an output similar to the one above but repeated three times for all three documents saved with the Map command will be returned.

[ { ref: Ref(Collection("songs"), "207089200754854408"),
 ts: 1533754501878440,
 data: { titolo: "Luna" } },
 { ref: Ref(Collection("songs"), "207089200754853384"),
 ts: 1533754501878440,
 data: { titolo: "I giardini di marzo" } },
 { ref: Ref(Collection("songs"), "207089200754852360"),
 ts: 1533754501878440,
 data: { titolo: "Rebel Rebel" } } ]

Updating the data in the database

To update the fields of a document, registered in a collection of the database, you can use the Update command :

my_database> Update(
 Ref(Collection("songs"), "207089183860195845"),
 { data: { song_title: "Kalimba de Luna" } }
)

Inside the command, in the example:

  • The first string is used to identify a document of the song collection with an ID corresponding to the one indicated;
  • The second string is used to indicate that the title field of that document is the one to be updated, by inserting the new Kalimba de Luna value.

Deleting documents or collections

As you have learned, FaunaDB represents data as documents belonging to collections. To make a comparison with SQL, this procedure would correspond to saving records in tables.

When you want to delete data, there’s a procedure to "empty" a collection of all its documents.

The first step is to build an index that points to all the elements of the collection:

my_database> CreateIndex({
 name: "all_songs",
 source: Collection("songs")
})

Not having specified the terms the index will point to all the documents present in the song collection.

Now, it's time to proceed with the deletion of all elements, via the Map command concatenated with a delete function:

my_database> Map(
 Paginate(
 Match(Index("all_songs"))
 ),
 Lambda("X", Delete(Var("X")))
)

In the example above:

  • Map will get all the documents pointed to by the all_brane index
  • Lambda is a function that will perform the deletion of the pointed elements.

At this point, all the elements of a collection will have been removed. However, in terms of the data, only the instances will not be there anymore, not the structure created. To proceed, in case it is no longer needed, the collection and the index will have to be eliminated as well.

To do so, just use the a Delete command :

my_database> Delete(Collection("songs"))
my_database> Delete(Index("all_songs"))

With this pair of commands, you will have deleted the song collection and, subsequently, the index associated with that collection.

Obtaining data from the Fauna database through queries

Getting all the documents in a collection and use indexes

Each document, upon its creation, is associated with a unique ID that can be used to identify that entity within the collections.

A first simple search that you could use is that of the ID of the document concerned. To do so, use the command:

my_database> Get(Ref(Collection("songs"), "207089200754852360"))

This ID should match that of the song " Rebel Rebel", previously entered in the song collection.

The resulting output should look as follows:

{ ref: Ref(Collection("songs"), "207089200754852360"),
 ts: 1533754501878440,
 data: { title: "Rebel Rebel" } }

Another possibility is to use an index, defined earlier in the guide.

my_database> Get(
Match(
 Index("songs_for_title"),
 "I giardini di marzo"
 )
 )

In this example, the song " I giardini di Marzo" was searched using the index "songs_by_title". The database will return this output:

{ ref: Ref(Collection("songs"), "207089200754853384"),
 ts: 1533754501878440,
 data: { title: "I giardini di marzo" } }

If, on the other hand, you want to get all the data from a DB collection, without applying any filter, just use a command with the help of an index, as previously shown.

my_database> CreateIndex({
 name: "all_songs",
 source: Collection("songs")
})

The all_songs index selects each document in the song collection. Next, resort to the command:

Map(
 Paginate(
 Match(Index("all_songs"))
 ),
 Lambda("X", Get(Var("X")))
)

In the code, the Lambda function will apply the Get function to the all_songs index.

Value matching filter

Documents that have a field corresponding to a certain value, specified by you, can also be searched.

First, start, as always, by defining an index:

my_database> CreateIndex({
 name: "songs_for_year",
 source: Collection("songs")
 terms: [{ field: ["data", "year"] }]
})

Next, apply a command as fowollows:

my_database>
 Map(
 Paginate(
 Match(Index("songs_for_year"), 2020)
 ),
 Lambda("X", Get(Var("X")))
)

With this query, the songs belonging to the songs_per_year index, only those of the year 2020, will have been selected.

For making a query similar to the one above, filter songs NOT with a year other than 2020.

Map(
 Paginate(
 Difference(
 Match(Index("all_songs")),
 Match(Index("songs_for_year"), 2020)
 )
 ),
 Lambda("x", Get(Var("x")))
)

The diversity, in this case, is in the use of the Difference function.

Filter by comparison

Other applicable filters are those about comparing values ​​of a field with a value defined by you.

By using the tracks_per_year index, a filter that is not based only on the sign of equality but also on the greater or lesser sign can be applied.

Map(
 Paginate(
 Match(Index("songs_for_year")),
 { after: 2010 }
 ),
 Lambda("x", Get(Select(1, Var("x"))))
)

In the example, the after specification serves to consider values ​​greater than or equal to the 2010 value.

Aggregating the data

With the help of indexes, data can be aggregated by using tricks that allow you to obtain the maximum or minimum values ​​of a grouping of values.

CreateIndex({
 name: "songs_for_artist",
 source: Collection("songs"),
 values: [{ field: ["data","artist"] }]
})

The first index, collects the songs by artist:

CreateIndex({
 name: "songs_for_length",
 source: Collection("songs"),
 terms: [{ field: ["data","artist"] }],
 values: [{ field: ["data","song_length"] }]
})

Imagine having a field for each song to represent the length of that track, the second index selects the duration for each title. Next, it orders them starting with the one with the longest duration.

Finally, through the functions, the songs will be retrieved grouped by artist, and, for each of them, the track length with the longest duration will be indicated:

Map(
 Paginate(
 Distinct(
 Match(Index("songs_for_artist"))
 )
 ),
 gid => Get(
 Match(Index("songs_for_length"), Gid)
 )
)

Conclusions

By now you should have gained the basic knowledge for interacting better with FaunaDB and use it to increase the performance and security of your serverless applications. 

It is recommended to learn more about the concepts related to this database by visiting the  official FaunaDB documentation  and discover the  FaunaDB Functions  and  Data Types  .