Learn the basics of FaunaDB by modeling a social graph in this beginner-friendly database tutorial. https://fireship.io/lessons/fauna-db-quickstart

Fauna https://fauna.com

Source Code https://github.com/fireship-io/faunadb-basics
Sponsor me for $1 on github https://github.com/codediodeio

#faunaDB #serverless #database

Install the quiz app 🤓

iOS https://itunes.apple.com/us/app/fireship/id1462592372?mt=8
Android https://play.google.com/store/apps/details?id=io.fireship.quizapp

Upgrade to Fireship PRO at https://fireship.io/pro
Use code lORhwXd2 for 25% off your first payment. 

My VS Code Theme

- Atom One Dark 
- vscode-icons
- Fira Code Font
2024-02-04T06:05:02.352Z
nova-2
2-general-nova
2024-01-09.29447
30089e05-99d1-4376-b32e-c263170674af
ac515775-8d60-4373-971a-3c6d7ef12cda
beec31e8e7198203b54dc4d2b4c51d9d9031f013968801bf1b61e2d9b8fe9975
67875a7f-c9c4-48a0-aa55-5bdb8a91c34a
deprecated
When you build an app, one of the main pain points that you'll face is your database.
You often hear developers debate the merits of SQL versus NoSQL.
On one hand, you have safety, security, and consistency.
And, on the other, you have flexibility, scalability, and productivity.
But, what if there's a database that could put an end to this debate once and for all?
Fauna DB is the cloud database that I've always dreamed of.
It's entirely serverless, so we don't have to provision anything and we only pay for what we actually use beyond the free tier.
It's as easy to use as a document database.
And, you can manage your data from its web interface or the command line.
It's extremely fast and scales infinitely in the cloud and is the 1st database in the world to implement a Calvin model for partition database systems.
Most importantly though, is its ability to handle complex data modeling use cases, like the ones you would find in a relational, no graph or time series database.
Over the next few minutes, you'll learn everything you need to know to get up and running with FaunaDB.
We'll use it to model the data relationships tips that you would find on Twitter.
A user has many tweets, users can follow each other, and retrieve a feed of tweets from all the users that they follow.
We'll write our code in Node.
Js, and by the end of the video, you'll have an API that you can use to connect to your front end application.
If you're new here, like and subscribe and check out the full write up on FireShip IO.
To follow along today, the first thing you'll need is a free Fauna account.
Once logged in, you'll see the Fauna dashboard.
At this point, you won't have a database, so go ahead and click the button to create a new one.
This is what's known as a top level database, and an awesome thing about Fauna is that it supports multi tenancy.
It's beyond the scope of this video, but a cool feature you should know about.
A database can have an unlimited number of child databases, allowing you to scope data and privileges to a specific organization or team.
In most cases, though, you'll just need one single database for your entire per application.
Now that we have a database, we'll create a collection.
A collection is like an SQL table and works very similar to other document oriented databases like MongoDB or Firestore.
A collection is kind of like a folder that contains many documents, then you can make queries against that collection to filter out a set of documents that you need for your front end UI.
When you create a collection, you give it a name, which is usually plural.
And in our case, it will store all of our user data.
Now a unique thing about Fauna is that you'll also notice an option for history.
It retains all of the changes that happen to a document over time.
When you write to the database, Fauna never actually changes a stored document.
Instead, it creates a copy of the original with the changes, then archives the original document to the history.
That's extremely useful when working with time series data and also for time traveling through any changes to your data.
You also have a TTL or time to live option, which can automatically delete ephemeral data that you no longer need.
Now that we have our user's collection, let's go ahead and add a document to it.
A document is represented as a plain JavaScript object.
The data you save here does not need to follow a rigid structure.
However, when you query multiple documents from a collection, it's based on the keys in this object.
So if we want to match all of the users with a certain name or email address, we'll want to use the same key name in every document.
Go ahead and click save, and now you should see that document in the collection.
What you'll notice is that it's automatically assigned a unique ID to the document.
Now if we expand the document, you can see in addition to our custom data, we also have a ref property that points to the user's collection along with that unique ID.
The reference is very important because, eventually, we'll use it to join data together from multiple collections.
In our case, for example, we could save a reference to this user on a tweet document so we know who a tweet belongs to, which is very similar to a foreign key in an SQL database.
At this point, I'm going to add a few more users to the database, and now we need to think about how we want to access this data.
There are multiple native APIs you can use to access data and Fauna.
The first one that you might be familiar with is GraphQL.
That's not the API we'll be using in this video.
However, if you're familiar with GraphQL, you can actually upload a schema to Fauna and it will automatically create the collections and indexes required to retrieve your data based on that schema.
It's really powerful stuff, but I think to really understand Fauna, you should learn its custom query language called FQL.
You can execute FQL right here on the console, or you can install FaunaShell on your local system to execute it from the command line.
And a little bit later, we'll learn how to use it in Node.
Js.
SQL is a functional language and is very intuitive and flexible, but there is a lot to learn.
And I recommend keeping the SQL cheat sheet nearby.
We'll look at about 10 of the most common functions, but just keep in mind that SQL can do a lot more than I present in this video.
One of the first functions you'll wanna know is get, which retrieves a single document based on a reference.
Get is just a function that takes a reference as an argument.
We make a reference with the ref function, which takes a collection and a document ID as its arguments.
If we then execute the query, we get the document data back as a result.
And, as an added bonus, you'll notice if we hover over the information icon, it will tell us exactly how many bytes were transferred and a bunch of other useful information.
Now, reading a single document is very easy when you have the ID, but in the real world, the document ID might not be readily available.
And that brings us to our next big topic, Indexes.
An index provides a way for you to define how to query documents from a collection.
For example, we might want to fetch To user based on their email address or username instead of the actual document ID.
A collection can have millions of documents, so an index provides a way to create a lookup table to quickly retrieve documents based on their actual internal data.
1st, we'll give our index a name, which in our case will be users by name.
From there, we can specify 1 or more terms, which is a field on the document itself that can be searched.
In our case, every user document has a name and we want to be able to fetch a user by the name.
By default, the index will only return the document reference.
But, another cool thing about Fauna is that you can tell the database which values from the document you want to return.
In other words, you search a document by the username and then return the email address or whatever other data you want for the UI.
That's an extremely useful little feature and we'll put it to use later in the video.
Now, let's go back to the shell and we'll see how we can read a document with this index.
Inside of git, we'll use the match function to search across an index.
It takes the index as its first argument and then an array of search terms as the second argument.
In this case, we just have the username which we can add as the second argument.
And go ahead and execute the query, and you should get that same document back as the result.
Now that we've explored the Fonta dashboard a little bit, we're going to switch gears into an actual Node JS application.
Our goal is to build a simple REST API with Express that enables us to read and write to the database with our own custom code by making HTTP requests.
You can follow along at this point by opening your IDE to an empty directory.
You'll need to have Node JS installed on your system, and I'd also recommend installing the Fauna v s code extension.
It allows you to see all of your collections and indexes right here in Versus Code, which is much easier than going back and forth to the dashboard.
From this empty directory, we'll initialize a new npm project by running npm init with the y flag.
That will give us a package JSON and then we can install FaunaDB and Express.
From there, I'll create a source directory and add an index dotjs file to it, which is where we'll write all of our source code.
Inside this file, we'll first require express, which will serve all of our API endpoints.
And to interact with the database, we'll require FaunaDB and initialize the FaunaDB client.
The client will connect your source code to the actual database in the cloud.
And to do that, it requires a secret key, so let's head back to the Fauna dashboard.
Board.
Find the security tab, then create a new key to authenticate your server.
By default, it gives you the choice between an admin and a server key.
For our use case, we just need a server key.
However, I would like to point out that you can implement fine grain access control right here from the Fauna dashboard.
That makes it easy to follow the principle of least privilege where you only grant access to the bare minimum set of operations that are actually needed on the server.
In any case, go ahead and copy the server key and then paste it into the Fonta DB client.
The next thing we'll do in this file is start up our express server by calling app listen on port 5000.
Now if you open the command line and run node pointed to your source directory, It will start up the server.
And keep in mind that you'll need to restart it anytime the code changes.
If that's too annoying for you, then check out nodemon to automatically reload anytime there's a change.
Now, if you remember earlier, I mentioned that SQL is a functional language and we can import those functions and use them in JavaScript from the FaunaDB query namespace.
As you can see, I've imported 10 different functions here and you don't need to know what they do at this point.
The only important thing to know is that we use these functions to interact with the database.
Now let's go ahead and set up our 1st API endpoint to read an individual tweet.
We'll use express to set up a get endpoint that points to a tweet with its ID in the URL.
Then for the callback, we'll set up an async function because any query you make to Fauna will return a promise.
For this endpoint, we simply want to read a single document like we did earlier from the shell in the Fauna dashboard.
Then we'll use the document itself as the response.
We can make a request to Fauna for a document by awaiting a client query.
Query takes an SQL expression as its argument.
And remember, it's a functional language, so what you end up doing here is composing multiple JavaScript functions together.
Conceptually, it's very similar to component composition in a UI framework like React.
We'll start with the get function to read a single document, Then we use the ref function to make a reference to the document that we want.
Ref takes 2 arguments.
1 is the collection that we want to read from, And the second is the document ID, which we'll get from the request parameters ID in the URL.
And that's basically all there is to it.
The promise will resolve with the actual document data, which we then send back as the response.
One thing we're not doing here though is catching errors, but that would be a good idea.
You can wrap the code in a try catch block, or you could simply chain the catch method to the other end of the promise.
Now let's go ahead and test it out.
At this point, we don't have any tweets in the database, So let's go back to Fauna and create a new collection for tweets, and then we'll add a document to it with the text of hello, world.
Once created, go ahead and copy the document ID.
Now at this point, we need to make a request to the URL.
In my case, I'm using an HTTP client known as Insomnia.
However, you could just use curl from the command line or a Versus Code extension to make these requests.
In any case, what we need to do is make a get request to local host 5000/tweet followed by the tweet ID.
When we send it, we should get the document back including the document data with the text of hello, world.
Now that we know our API is working, we're going to look at some more complex examples of relational data.
In this app, a user can have many tweets.
But how do we connect a user document to a tweet document?
Well, first, we need a way to create a tweet.
And to handle that, we'll create a post endpoint that points to the tweet URL, and then we'll start with the same async function setup that we used in the previous endpoint.
Creating a document is really easy.
We just use the create function, point to the collection we want, and then pass it whatever custom data we want to save there.
When we construct the data object, we can use regular JavaScript values or we can use SQL functions to get data from the database.
In this case, we want the user field to be a reference to another user document in Fauna.
There are many possible ways to do this, but one way is to use the select function, which will select a specific value from a document, which in this case is the reference.
Now at this point, we might assume we only have the username, In which case, we can use our index, users by name, to get the corresponding user document reference.
So the main takeaway here is that you can read 1 or more documents when performing some kind of other operation like a write to the database.
And that allows you to model relational data in a way that's very similar to an SQL database with foreign keys.
And it's also worth noting that Fauna is 100% ACID compliant, which means when you run this database transaction, it'll be globally consistent.
Or, in other words, all future reads will reflect the value of the write, even when distributed across thousands of users around the world.
If we go back to our HTTP client, We can make a post request to local host 5000/ tweet.
Then we should get the newly created tweet back as the response.
And And if you go to the Fauna dashboard, you should see it created in the user's collection there as well.
Now that we have multiple tweets in the database, let's create an endpoint that can retrieve or query multiple tweets based on a username.
Before we can make that query, we'll need an index.
So let's go back to the Fauna dashboard and create a new index called tweets by user.
The field we want to index here is the user reference to give us all the tweets owned by a user.
And because we already have the user reference, we don't really need to have that returned on every single document.
We can tell Fauna to only return the tweet text by setting it as a value.
That way, we're only returning the actual data that we need for the UI.
When we make this query, it's very similar to reading a single document, but instead of git, we use the paginate function.
The difference here is that git returns the first match whereas paginate will return a set of documents that match that query.
We then point to the index and then use select to grab the reference to the user.
Now there is one thing that is bothering me at this point.
We have some code duplication going on in our code base.
Notice we're using the same exact select code for this query as we are in the previous endpoint.
And getting a user is something we'll do often, so it's only going to get worse as we move forward.
And that brings us to yet another awesome feature in Fauna called functions.
Go ahead and copy the duplicated code and then head over to the Fauna dashboard and find the functions tab.
A function allows you to Strack some SQL code so it can be used on any server or any platform.
We'll give our function a name of get user and then apply it to the server role.
Then in the function body, we have a query followed by a Lambda function.
If you're not familiar with the Lambda function, just think of it like an anonymous arrow function in JavaScript.
The value of x is something we pass into the function, then in the function body, we'll add our duplicated code.
Instead of the hard coded username, we'll add a variable that points to x.
And then we'll actually change the name of x to user just to make our code a little more readable.
Now we can go back into our node app and reference this function.
We'll need to import call and function.
And And when you import function, you want to rename it something else using a colon because it collides with the built in function in JavaScript.
Next, Let's find the duplicated lines of code that we want to replace.
Now we can call the function by its name, get user, and then pass in whatever custom argument we want here, and it will be executed by Fonta remotely.
So if you ever need to update this code, it gets updated throughout your entire code base atomically.
The bottom line here is that functions provide an awesome way to keep your concise and maintainable.
What we created is a one to many relationship where a user has many tweets, and a tweet belongs to a user.
What we're going to look at next is the relationship between users, where a user can follow another user and or be followed by that user.
Or in other words, a user can have and belong to many different relationships.
It's your typical social graph data model.
1st, we'll go to the Fauna dashboard and create a new collection for relationships.
Each document in this collection will contain a follower and a whose values are user document references.
You can think of this document as an edge in a graph that connects 2 user accounts together, a one way graph where the follower points to the followee.
Back in our code, we'll set up a new relationship endpoint That creates the relationship document.
It creates a document just like we did for a tweet.
The only difference is that we point to the relationship's collection.
In the data object, the follower and the followee are just user references, which we can get by calling our get user function that we created previously.
For now, we'll just hard code a couple of usernames in here to show that Bob follows Fireship.
We can now go ahead and make a post request to the relationship endpoint and we should get a new document back that has a follower and a with a user reference on it.
Now that we can establish a relationship, I want to show you how we can get all of the accounts that are followed by a given user.
And not just the accounts, but also the tweets that are owned by those accounts so we can show the end user a feed of tweets from the people that they follow.
The first step, of course, will be to create a new index, which will give a name of followers by followee.
It will take the followee's user reference then return all the accounts that that user is following.
From there, we'll go back to our code and create a new get endpoint for feed.
We'll again use the paginate function in the query, but this time, instead of retrieving a single index, we're going to join 2 indexes together.
The join function takes 2 arguments.
The first one is the initial thing that you want to query, which in our case is all the followed users, which we can get by pointing to our recently created index and then a specific username like Bob.
That will give us all of the user references that are followed by Bob.
We can then join all the tweets from those users by using the index tweets by user as the second argument.
If we go ahead and make that request, You can see that we now get the text from multiple tweets back from that index, and there's a lot more we could do with joins here.
Instead of returning the entire index, we could use a Lambda function to filter and sort the results with our own custom logic.
But, I think we'll save that for a future video.
I'm gonna go ahead and wrap things up there.
Fauna is a truly awesome database and the more I use it, the more I like it.
If I were starting a new project today, Fauna would definitely be at the top of my list for the tech stack.
If you wanna see more videos on this topic, let me know in the comments.
Consider supporting my work with a GitHub sponsorship, or by becoming a pro member at Fireship IO.
Thanks for watching, and I will see you in the next one.

Speaker 0: When you build an app, one of the main pain points that you'll face is your database. You often hear developers debate the merits of SQL versus NoSQL. On one hand, you have safety, security, and consistency. And, on the other, you have flexibility, scalability, and productivity. But, what if there's a database that could put an end to this debate once and for all?

Fauna DB is the cloud database that I've always dreamed of. It's entirely serverless, so we don't have to provision anything and we only pay for what we actually use beyond the free tier. It's as easy to use as a document database. And, you can manage your data from its web interface or the command line. It's extremely fast and scales infinitely in the cloud and is the 1st database in the world to implement a Calvin model for partition database systems.

Most importantly though, is its ability to handle complex data modeling use cases, like the ones you would find in a relational, no graph or time series database. Over the next few minutes, you'll learn everything you need to know to get up and running with FaunaDB. We'll use it to model the data relationships tips that you would find on Twitter. A user has many tweets, users can follow each other, and retrieve a feed of tweets from all the users that they follow. We'll write our code in Node.

Js, and by the end of the video, you'll have an API that you can use to connect to your front end application. If you're new here, like and subscribe and check out the full write up on FireShip IO. To follow along today, the first thing you'll need is a free Fauna account. Once logged in, you'll see the Fauna dashboard. At this point, you won't have a database, so go ahead and click the button to create a new one.

This is what's known as a top level database, and an awesome thing about Fauna is that it supports multi tenancy. It's beyond the scope of this video, but a cool feature you should know about. A database can have an unlimited number of child databases, allowing you to scope data and privileges to a specific organization or team. In most cases, though, you'll just need one single database for your entire per application. Now that we have a database, we'll create a collection.

A collection is like an SQL table and works very similar to other document oriented databases like MongoDB or Firestore. A collection is kind of like a folder that contains many documents, then you can make queries against that collection to filter out a set of documents that you need for your front end UI. When you create a collection, you give it a name, which is usually plural. And in our case, it will store all of our user data. Now a unique thing about Fauna is that you'll also notice an option for history.

It retains all of the changes that happen to a document over time. When you write to the database, Fauna never actually changes a stored document. Instead, it creates a copy of the original with the changes, then archives the original document to the history. That's extremely useful when working with time series data and also for time traveling through any changes to your data. You also have a TTL or time to live option, which can automatically delete ephemeral data that you no longer need.

Now that we have our user's collection, let's go ahead and add a document to it. A document is represented as a plain JavaScript object. The data you save here does not need to follow a rigid structure. However, when you query multiple documents from a collection, it's based on the keys in this object. So if we want to match all of the users with a certain name or email address, we'll want to use the same key name in every document.

Go ahead and click save, and now you should see that document in the collection. What you'll notice is that it's automatically assigned a unique ID to the document. Now if we expand the document, you can see in addition to our custom data, we also have a ref property that points to the user's collection along with that unique ID. The reference is very important because, eventually, we'll use it to join data together from multiple collections. In our case, for example, we could save a reference to this user on a tweet document so we know who a tweet belongs to, which is very similar to a foreign key in an SQL database.

At this point, I'm going to add a few more users to the database, and now we need to think about how we want to access this data. There are multiple native APIs you can use to access data and Fauna. The first one that you might be familiar with is GraphQL. That's not the API we'll be using in this video. However, if you're familiar with GraphQL, you can actually upload a schema to Fauna and it will automatically create the collections and indexes required to retrieve your data based on that schema.

It's really powerful stuff, but I think to really understand Fauna, you should learn its custom query language called FQL. You can execute FQL right here on the console, or you can install FaunaShell on your local system to execute it from the command line. And a little bit later, we'll learn how to use it in Node. Js. SQL is a functional language and is very intuitive and flexible, but there is a lot to learn.

And I recommend keeping the SQL cheat sheet nearby. We'll look at about 10 of the most common functions, but just keep in mind that SQL can do a lot more than I present in this video. One of the first functions you'll wanna know is get, which retrieves a single document based on a reference. Get is just a function that takes a reference as an argument. We make a reference with the ref function, which takes a collection and a document ID as its arguments.

If we then execute the query, we get the document data back as a result. And, as an added bonus, you'll notice if we hover over the information icon, it will tell us exactly how many bytes were transferred and a bunch of other useful information. Now, reading a single document is very easy when you have the ID, but in the real world, the document ID might not be readily available. And that brings us to our next big topic, Indexes. An index provides a way for you to define how to query documents from a collection.

For example, we might want to fetch To user based on their email address or username instead of the actual document ID. A collection can have millions of documents, so an index provides a way to create a lookup table to quickly retrieve documents based on their actual internal data. 1st, we'll give our index a name, which in our case will be users by name. From there, we can specify 1 or more terms, which is a field on the document itself that can be searched. In our case, every user document has a name and we want to be able to fetch a user by the name.

By default, the index will only return the document reference. But, another cool thing about Fauna is that you can tell the database which values from the document you want to return. In other words, you search a document by the username and then return the email address or whatever other data you want for the UI. That's an extremely useful little feature and we'll put it to use later in the video. Now, let's go back to the shell and we'll see how we can read a document with this index.

Inside of git, we'll use the match function to search across an index. It takes the index as its first argument and then an array of search terms as the second argument. In this case, we just have the username which we can add as the second argument. And go ahead and execute the query, and you should get that same document back as the result. Now that we've explored the Fonta dashboard a little bit, we're going to switch gears into an actual Node JS application.

Our goal is to build a simple REST API with Express that enables us to read and write to the database with our own custom code by making HTTP requests. You can follow along at this point by opening your IDE to an empty directory. You'll need to have Node JS installed on your system, and I'd also recommend installing the Fauna v s code extension. It allows you to see all of your collections and indexes right here in Versus Code, which is much easier than going back and forth to the dashboard. From this empty directory, we'll initialize a new npm project by running npm init with the y flag.

That will give us a package JSON and then we can install FaunaDB and Express. From there, I'll create a source directory and add an index dotjs file to it, which is where we'll write all of our source code. Inside this file, we'll first require express, which will serve all of our API endpoints. And to interact with the database, we'll require FaunaDB and initialize the FaunaDB client. The client will connect your source code to the actual database in the cloud.

And to do that, it requires a secret key, so let's head back to the Fauna dashboard. Board. Find the security tab, then create a new key to authenticate your server. By default, it gives you the choice between an admin and a server key. For our use case, we just need a server key.

However, I would like to point out that you can implement fine grain access control right here from the Fauna dashboard. That makes it easy to follow the principle of least privilege where you only grant access to the bare minimum set of operations that are actually needed on the server. In any case, go ahead and copy the server key and then paste it into the Fonta DB client. The next thing we'll do in this file is start up our express server by calling app listen on port 5000. Now if you open the command line and run node pointed to your source directory, It will start up the server.

And keep in mind that you'll need to restart it anytime the code changes. If that's too annoying for you, then check out nodemon to automatically reload anytime there's a change. Now, if you remember earlier, I mentioned that SQL is a functional language and we can import those functions and use them in JavaScript from the FaunaDB query namespace. As you can see, I've imported 10 different functions here and you don't need to know what they do at this point. The only important thing to know is that we use these functions to interact with the database.

Now let's go ahead and set up our 1st API endpoint to read an individual tweet. We'll use express to set up a get endpoint that points to a tweet with its ID in the URL. Then for the callback, we'll set up an async function because any query you make to Fauna will return a promise. For this endpoint, we simply want to read a single document like we did earlier from the shell in the Fauna dashboard. Then we'll use the document itself as the response.

We can make a request to Fauna for a document by awaiting a client query. Query takes an SQL expression as its argument. And remember, it's a functional language, so what you end up doing here is composing multiple JavaScript functions together. Conceptually, it's very similar to component composition in a UI framework like React. We'll start with the get function to read a single document, Then we use the ref function to make a reference to the document that we want.

Ref takes 2 arguments. 1 is the collection that we want to read from, And the second is the document ID, which we'll get from the request parameters ID in the URL. And that's basically all there is to it. The promise will resolve with the actual document data, which we then send back as the response. One thing we're not doing here though is catching errors, but that would be a good idea.

You can wrap the code in a try catch block, or you could simply chain the catch method to the other end of the promise. Now let's go ahead and test it out. At this point, we don't have any tweets in the database, So let's go back to Fauna and create a new collection for tweets, and then we'll add a document to it with the text of hello, world. Once created, go ahead and copy the document ID. Now at this point, we need to make a request to the URL.

In my case, I'm using an HTTP client known as Insomnia. However, you could just use curl from the command line or a Versus Code extension to make these requests. In any case, what we need to do is make a get request to local host 5000/tweet followed by the tweet ID. When we send it, we should get the document back including the document data with the text of hello, world. Now that we know our API is working, we're going to look at some more complex examples of relational data.

In this app, a user can have many tweets. But how do we connect a user document to a tweet document? Well, first, we need a way to create a tweet. And to handle that, we'll create a post endpoint that points to the tweet URL, and then we'll start with the same async function setup that we used in the previous endpoint. Creating a document is really easy.

We just use the create function, point to the collection we want, and then pass it whatever custom data we want to save there. When we construct the data object, we can use regular JavaScript values or we can use SQL functions to get data from the database. In this case, we want the user field to be a reference to another user document in Fauna. There are many possible ways to do this, but one way is to use the select function, which will select a specific value from a document, which in this case is the reference. Now at this point, we might assume we only have the username, In which case, we can use our index, users by name, to get the corresponding user document reference.

So the main takeaway here is that you can read 1 or more documents when performing some kind of other operation like a write to the database. And that allows you to model relational data in a way that's very similar to an SQL database with foreign keys. And it's also worth noting that Fauna is 100% ACID compliant, which means when you run this database transaction, it'll be globally consistent. Or, in other words, all future reads will reflect the value of the write, even when distributed across thousands of users around the world. If we go back to our HTTP client, We can make a post request to local host 5000/ tweet.

Then we should get the newly created tweet back as the response. And And if you go to the Fauna dashboard, you should see it created in the user's collection there as well. Now that we have multiple tweets in the database, let's create an endpoint that can retrieve or query multiple tweets based on a username. Before we can make that query, we'll need an index. So let's go back to the Fauna dashboard and create a new index called tweets by user.

The field we want to index here is the user reference to give us all the tweets owned by a user. And because we already have the user reference, we don't really need to have that returned on every single document. We can tell Fauna to only return the tweet text by setting it as a value. That way, we're only returning the actual data that we need for the UI. When we make this query, it's very similar to reading a single document, but instead of git, we use the paginate function.

The difference here is that git returns the first match whereas paginate will return a set of documents that match that query. We then point to the index and then use select to grab the reference to the user. Now there is one thing that is bothering me at this point. We have some code duplication going on in our code base. Notice we're using the same exact select code for this query as we are in the previous endpoint.

And getting a user is something we'll do often, so it's only going to get worse as we move forward. And that brings us to yet another awesome feature in Fauna called functions. Go ahead and copy the duplicated code and then head over to the Fauna dashboard and find the functions tab. A function allows you to Strack some SQL code so it can be used on any server or any platform. We'll give our function a name of get user and then apply it to the server role.

Then in the function body, we have a query followed by a Lambda function. If you're not familiar with the Lambda function, just think of it like an anonymous arrow function in JavaScript. The value of x is something we pass into the function, then in the function body, we'll add our duplicated code. Instead of the hard coded username, we'll add a variable that points to x. And then we'll actually change the name of x to user just to make our code a little more readable.

Now we can go back into our node app and reference this function. We'll need to import call and function. And And when you import function, you want to rename it something else using a colon because it collides with the built in function in JavaScript. Next, Let's find the duplicated lines of code that we want to replace. Now we can call the function by its name, get user, and then pass in whatever custom argument we want here, and it will be executed by Fonta remotely.

So if you ever need to update this code, it gets updated throughout your entire code base atomically. The bottom line here is that functions provide an awesome way to keep your concise and maintainable. What we created is a one to many relationship where a user has many tweets, and a tweet belongs to a user. What we're going to look at next is the relationship between users, where a user can follow another user and or be followed by that user. Or in other words, a user can have and belong to many different relationships.

It's your typical social graph data model. 1st, we'll go to the Fauna dashboard and create a new collection for relationships. Each document in this collection will contain a follower and a whose values are user document references. You can think of this document as an edge in a graph that connects 2 user accounts together, a one way graph where the follower points to the followee. Back in our code, we'll set up a new relationship endpoint That creates the relationship document.

It creates a document just like we did for a tweet. The only difference is that we point to the relationship's collection. In the data object, the follower and the followee are just user references, which we can get by calling our get user function that we created previously. For now, we'll just hard code a couple of usernames in here to show that Bob follows Fireship. We can now go ahead and make a post request to the relationship endpoint and we should get a new document back that has a follower and a with a user reference on it.

Now that we can establish a relationship, I want to show you how we can get all of the accounts that are followed by a given user. And not just the accounts, but also the tweets that are owned by those accounts so we can show the end user a feed of tweets from the people that they follow. The first step, of course, will be to create a new index, which will give a name of followers by followee. It will take the followee's user reference then return all the accounts that that user is following. From there, we'll go back to our code and create a new get endpoint for feed.

We'll again use the paginate function in the query, but this time, instead of retrieving a single index, we're going to join 2 indexes together. The join function takes 2 arguments. The first one is the initial thing that you want to query, which in our case is all the followed users, which we can get by pointing to our recently created index and then a specific username like Bob. That will give us all of the user references that are followed by Bob. We can then join all the tweets from those users by using the index tweets by user as the second argument.

If we go ahead and make that request, You can see that we now get the text from multiple tweets back from that index, and there's a lot more we could do with joins here. Instead of returning the entire index, we could use a Lambda function to filter and sort the results with our own custom logic. But, I think we'll save that for a future video. I'm gonna go ahead and wrap things up there. Fauna is a truly awesome database and the more I use it, the more I like it.

If I were starting a new project today, Fauna would definitely be at the top of my list for the tech stack. If you wanna see more videos on this topic, let me know in the comments. Consider supporting my work with a GitHub sponsorship, or by becoming a pro member at Fireship IO. Thanks for watching, and I will see you in the next one.
When you build an app, one of the main pain points that you'll face is your database. You often hear developers debate the merits of SQL versus NoSQL. On one hand, you have safety, security, and consistency. And, on the other, you have flexibility, scalability, and productivity. But, what if there's a database that could put an end to this debate once and for all? Fauna DB is the cloud database that I've always dreamed of. It's entirely serverless, so we don't have to provision anything and we only pay for what we actually use beyond the free tier. It's as easy to use as a document database. And, you can manage your data from its web interface or the command line. It's extremely fast and scales infinitely in the cloud and is the 1st database in the world to implement a Calvin model for partition database systems. Most importantly though, is its ability to handle complex data modeling use cases, like the ones you would find in a relational, no graph or time series database. Over the next few minutes, you'll learn everything you need to know to get up and running with FaunaDB. We'll use it to model the data relationships tips that you would find on Twitter. A user has many tweets, users can follow each other, and retrieve a feed of tweets from all the users that they follow. We'll write our code in Node. Js, and by the end of the video, you'll have an API that you can use to connect to your front end application.
twitter
databases
data management
data analysis
data
social media
wildlife
modeling
software
If you're new here, like and subscribe and check out the full write up on FireShip IO.
To follow along today, the first thing you'll need is a free Fauna account. Once logged in, you'll see the Fauna dashboard. At this point, you won't have a database, so go ahead and click the button to create a new one. This is what's known as a top level database, and an awesome thing about Fauna is that it supports multi tenancy. It's beyond the scope of this video, but a cool feature you should know about. A database can have an unlimited number of child databases, allowing you to scope data and privileges to a specific organization or team. In most cases, though, you'll just need one single database for your entire per application. Now that we have a database, we'll create a collection. A collection is like an SQL table and works very similar to other document oriented databases like MongoDB or Firestore. A collection is kind of like a folder that contains many documents, then you can make queries against that collection to filter out a set of documents that you need for your front end UI.
databases
wildlife
ecology
data management
When you create a collection, you give it a name, which is usually plural. And in our case, it will store all of our user data. Now a unique thing about Fauna is that you'll also notice an option for history. It retains all of the changes that happen to a document over time. When you write to the database, Fauna never actually changes a stored document. Instead, it creates a copy of the original with the changes, then archives the original document to the history. That's extremely useful when working with time series data and also for time traveling through any changes to your data. You also have a TTL or time to live option, which can automatically delete ephemeral data that you no longer need. Now that we have our user's collection, let's go ahead and add a document to it. A document is represented as a plain JavaScript object. The data you save here does not need to follow a rigid structure. However, when you query multiple documents from a collection, it's based on the keys in this object.
databases
data management
wildlife
data
documentation
dinosaurs
So if we want to match all of the users with a certain name or email address, we'll want to use the same key name in every document. Go ahead and click save, and now you should see that document in the collection. What you'll notice is that it's automatically assigned a unique ID to the document.
Now if we expand the document, you can see in addition to our custom data, we also have a ref property that points to the user's collection along with that unique ID. The reference is very important because, eventually, we'll use it to join data together from multiple collections. In our case, for example, we could save a reference to this user on a tweet document so we know who a tweet belongs to, which is very similar to a foreign key in an SQL database. At this point, I'm going to add a few more users to the database, and now we need to think about how we want to access this data. There are multiple native APIs you can use to access data and Fauna. The first one that you might be familiar with is GraphQL. That's not the API we'll be using in this video. However, if you're familiar with GraphQL, you can actually upload a schema to Fauna and it will automatically create the collections and indexes required to retrieve your data based on that schema. It's really powerful stuff, but I think to really understand Fauna, you should learn its custom query language called FQL. You can execute FQL right here on the console, or you can install FaunaShell on your local system to execute it from the command line. And a little bit later, we'll learn how to use it in Node. Js. SQL is a functional language and is very intuitive and flexible, but there is a lot to learn. And I recommend keeping the SQL cheat sheet nearby. We'll look at about 10 of the most common functions, but just keep in mind that SQL can do a lot more than I present in this video. One of the first functions you'll wanna know is get, which retrieves a single document based on a reference.
databases
data management
wildlife
twitter
data
Get is just a function that takes a reference as an argument.
We make a reference with the ref function, which takes a collection and a document ID as its arguments. If we then execute the query, we get the document data back as a result. And, as an added bonus, you'll notice if we hover over the information icon, it will tell us exactly how many bytes were transferred and a bunch of other useful information. Now, reading a single document is very easy when you have the ID, but in the real world, the document ID might not be readily available. And that brings us to our next big topic, Indexes. An index provides a way for you to define how to query documents from a collection. For example, we might want to fetch To user based on their email address or username instead of the actual document ID. A collection can have millions of documents, so an index provides a way to create a lookup table to quickly retrieve documents based on their actual internal data.
databases
reading
documentation
data
1st, we'll give our index a name, which in our case will be users by name. From there, we can specify 1 or more terms, which is a field on the document itself that can be searched.
In our case, every user document has a name and we want to be able to fetch a user by the name. By default, the index will only return the document reference. But, another cool thing about Fauna is that you can tell the database which values from the document you want to return. In other words, you search a document by the username and then return the email address or whatever other data you want for the UI. That's an extremely useful little feature and we'll put it to use later in the video.
wildlife
databases
Now, let's go back to the shell and we'll see how we can read a document with this index. Inside of git, we'll use the match function to search across an index. It takes the index as its first argument and then an array of search terms as the second argument. In this case, we just have the username which we can add as the second argument. And go ahead and execute the query, and you should get that same document back as the result. Now that we've explored the Fonta dashboard a little bit, we're going to switch gears into an actual Node JS application. Our goal is to build a simple REST API with Express that enables us to read and write to the database with our own custom code by making HTTP requests. You can follow along at this point by opening your IDE to an empty directory. You'll need to have Node JS installed on your system, and I'd also recommend installing the Fauna v s code extension.
It allows you to see all of your collections and indexes right here in Versus Code, which is much easier than going back and forth to the dashboard. From this empty directory, we'll initialize a new npm project by running npm init with the y flag. That will give us a package JSON and then we can install FaunaDB and Express.
databases
From there, I'll create a source directory and add an index dotjs file to it, which is where we'll write all of our source code. Inside this file, we'll first require express, which will serve all of our API endpoints. And to interact with the database, we'll require FaunaDB and initialize the FaunaDB client. The client will connect your source code to the actual database in the cloud. And to do that, it requires a secret key, so let's head back to the Fauna dashboard. Board. Find the security tab, then create a new key to authenticate your server. By default, it gives you the choice between an admin and a server key. For our use case, we just need a server key. However, I would like to point out that you can implement fine grain access control right here from the Fauna dashboard.
databases
security
wildlife
That makes it easy to follow the principle of least privilege where you only grant access to the bare minimum set of operations that are actually needed on the server. In any case, go ahead and copy the server key and then paste it into the Fonta DB client. The next thing we'll do in this file is start up our express server by calling app listen on port 5000. Now if you open the command line and run node pointed to your source directory, It will start up the server. And keep in mind that you'll need to restart it anytime the code changes.
If that's too annoying for you, then check out nodemon to automatically reload anytime there's a change. Now, if you remember earlier, I mentioned that SQL is a functional language and we can import those functions and use them in JavaScript from the FaunaDB query namespace. As you can see, I've imported 10 different functions here and you don't need to know what they do at this point.
databases
The only important thing to know is that we use these functions to interact with the database.
Now let's go ahead and set up our 1st API endpoint to read an individual tweet. We'll use express to set up a get endpoint that points to a tweet with its ID in the URL. Then for the callback, we'll set up an async function because any query you make to Fauna will return a promise. For this endpoint, we simply want to read a single document like we did earlier from the shell in the Fauna dashboard. Then we'll use the document itself as the response.
twitter
wildlife
We can make a request to Fauna for a document by awaiting a client query. Query takes an SQL expression as its argument. And remember, it's a functional language, so what you end up doing here is composing multiple JavaScript functions together. Conceptually, it's very similar to component composition in a UI framework like React.
We'll start with the get function to read a single document, Then we use the ref function to make a reference to the document that we want. Ref takes 2 arguments. 1 is the collection that we want to read from, And the second is the document ID, which we'll get from the request parameters ID in the URL. And that's basically all there is to it. The promise will resolve with the actual document data, which we then send back as the response.
documentation
One thing we're not doing here though is catching errors, but that would be a good idea. You can wrap the code in a try catch block, or you could simply chain the catch method to the other end of the promise. Now let's go ahead and test it out. At this point, we don't have any tweets in the database, So let's go back to Fauna and create a new collection for tweets, and then we'll add a document to it with the text of hello, world. Once created, go ahead and copy the document ID.
twitter
logic
gambling
Now at this point, we need to make a request to the URL. In my case, I'm using an HTTP client known as Insomnia.
However, you could just use curl from the command line or a Versus Code extension to make these requests. In any case, what we need to do is make a get request to local host 5000/tweet followed by the tweet ID. When we send it, we should get the document back including the document data with the text of hello, world. Now that we know our API is working, we're going to look at some more complex examples of relational data. In this app, a user can have many tweets. But how do we connect a user document to a tweet document? Well, first, we need a way to create a tweet. And to handle that, we'll create a post endpoint that points to the tweet URL, and then we'll start with the same async function setup that we used in the previous endpoint.
twitter
documentation
Creating a document is really easy. We just use the create function, point to the collection we want, and then pass it whatever custom data we want to save there. When we construct the data object, we can use regular JavaScript values or we can use SQL functions to get data from the database. In this case, we want the user field to be a reference to another user document in Fauna. There are many possible ways to do this, but one way is to use the select function, which will select a specific value from a document, which in this case is the reference.
databases
data
Now at this point, we might assume we only have the username, In which case, we can use our index, users by name, to get the corresponding user document reference. So the main takeaway here is that you can read 1 or more documents when performing some kind of other operation like a write to the database. And that allows you to model relational data in a way that's very similar to an SQL database with foreign keys. And it's also worth noting that Fauna is 100% ACID compliant, which means when you run this database transaction, it'll be globally consistent. Or, in other words, all future reads will reflect the value of the write, even when distributed across thousands of users around the world. If we go back to our HTTP client, We can make a post request to local host 5000/ tweet. Then we should get the newly created tweet back as the response. And And if you go to the Fauna dashboard, you should see it created in the user's collection there as well. Now that we have multiple tweets in the database, let's create an endpoint that can retrieve or query multiple tweets based on a username. Before we can make that query, we'll need an index. So let's go back to the Fauna dashboard and create a new index called tweets by user. The field we want to index here is the user reference to give us all the tweets owned by a user. And because we already have the user reference, we don't really need to have that returned on every single document. We can tell Fauna to only return the tweet text by setting it as a value. That way, we're only returning the actual data that we need for the UI.
databases
twitter
data
data management
blogging
reading
data analysis
When we make this query, it's very similar to reading a single document, but instead of git, we use the paginate function. The difference here is that git returns the first match whereas paginate will return a set of documents that match that query. We then point to the index and then use select to grab the reference to the user.
Now there is one thing that is bothering me at this point. We have some code duplication going on in our code base. Notice we're using the same exact select code for this query as we are in the previous endpoint. And getting a user is something we'll do often, so it's only going to get worse as we move forward. And that brings us to yet another awesome feature in Fauna called functions. Go ahead and copy the duplicated code and then head over to the Fauna dashboard and find the functions tab. A function allows you to Strack some SQL code so it can be used on any server or any platform. We'll give our function a name of get user and then apply it to the server role.
databases
programming
wildlife
Then in the function body, we have a query followed by a Lambda function. If you're not familiar with the Lambda function, just think of it like an anonymous arrow function in JavaScript. The value of x is something we pass into the function, then in the function body, we'll add our duplicated code.
Instead of the hard coded username, we'll add a variable that points to x. And then we'll actually change the name of x to user just to make our code a little more readable. Now we can go back into our node app and reference this function. We'll need to import call and function.
programming
And And when you import function, you want to rename it something else using a colon because it collides with the built in function in JavaScript. Next, Let's find the duplicated lines of code that we want to replace. Now we can call the function by its name, get user, and then pass in whatever custom argument we want here, and it will be executed by Fonta remotely.
So if you ever need to update this code, it gets updated throughout your entire code base atomically. The bottom line here is that functions provide an awesome way to keep your concise and maintainable. What we created is a one to many relationship where a user has many tweets, and a tweet belongs to a user. What we're going to look at next is the relationship between users, where a user can follow another user and or be followed by that user. Or in other words, a user can have and belong to many different relationships. It's your typical social graph data model. 1st, we'll go to the Fauna dashboard and create a new collection for relationships. Each document in this collection will contain a follower and a whose values are user document references.
relationships
twitter
databases
data
data management
social media
You can think of this document as an edge in a graph that connects 2 user accounts together, a one way graph where the follower points to the followee.
Back in our code, we'll set up a new relationship endpoint That creates the relationship document. It creates a document just like we did for a tweet. The only difference is that we point to the relationship's collection. In the data object, the follower and the followee are just user references, which we can get by calling our get user function that we created previously.
relationships
For now, we'll just hard code a couple of usernames in here to show that Bob follows Fireship. We can now go ahead and make a post request to the relationship endpoint and we should get a new document back that has a follower and a with a user reference on it.
Now that we can establish a relationship, I want to show you how we can get all of the accounts that are followed by a given user. And not just the accounts, but also the tweets that are owned by those accounts so we can show the end user a feed of tweets from the people that they follow. The first step, of course, will be to create a new index, which will give a name of followers by followee.
twitter
social media
instagram
It will take the followee's user reference then return all the accounts that that user is following.
From there, we'll go back to our code and create a new get endpoint for feed. We'll again use the paginate function in the query, but this time, instead of retrieving a single index, we're going to join 2 indexes together. The join function takes 2 arguments. The first one is the initial thing that you want to query, which in our case is all the followed users, which we can get by pointing to our recently created index and then a specific username like Bob.
databases
That will give us all of the user references that are followed by Bob. We can then join all the tweets from those users by using the index tweets by user as the second argument. If we go ahead and make that request, You can see that we now get the text from multiple tweets back from that index, and there's a lot more we could do with joins here. Instead of returning the entire index, we could use a Lambda function to filter and sort the results with our own custom logic. But, I think we'll save that for a future video. I'm gonna go ahead and wrap things up there. Fauna is a truly awesome database and the more I use it, the more I like it. If I were starting a new project today, Fauna would definitely be at the top of my list for the tech stack. If you wanna see more videos on this topic, let me know in the comments. Consider supporting my work with a GitHub sponsorship, or by becoming a pro member at Fireship IO. Thanks for watching, and I will see you in the next one.
wildlife
twitter
dinosaurs
databases
ecology
customer support
When you build an app, one of the main pain points that you'll face is your database. You often hear developers debate the merits of SQL versus NoSQL. On one hand, you have safety, security, and consistency. And, on the other, you have flexibility, scalability, and productivity. But, what if there's a database that could put an end to this debate once and for all? Fauna DB is the cloud database that I've always dreamed of. It's entirely serverless, so we don't have to provision anything and we only pay for what we actually use beyond the free tier. It's as easy to use as a document database. And, you can manage your data from its web interface or the command line. It's extremely fast and scales infinitely in the cloud and is the 1st database in the world to implement a Calvin model for partition database systems. Most importantly though, is its ability to handle complex data modeling use cases, like the ones you would find in a relational, no graph or time series database. Over the next few minutes, you'll learn everything you need to know to get up and running with FaunaDB. We'll use it to model the data relationships tips that you would find on Twitter. A user has many tweets, users can follow each other, and retrieve a feed of tweets from all the users that they follow. We'll write our code in Node. Js, and by the end of the video, you'll have an API that you can use to connect to your front end application. If you're new here, like and subscribe and check out the full write up on FireShip IO. To follow along today, the first thing you'll need is a free Fauna account. Once logged in, you'll see the Fauna dashboard. At this point, you won't have a database, so go ahead and click the button to create a new one. This is what's known as a top level database, and an awesome thing about Fauna is that it supports multi tenancy. It's beyond the scope of this video, but a cool feature you should know about. A database can have an unlimited number of child databases, allowing you to scope data and privileges to a specific organization or team. In most cases, though, you'll just need one single database for your entire per application. Now that we have a database, we'll create a collection. A collection is like an SQL table and works very similar to other document oriented databases like MongoDB or Firestore. A collection is kind of like a folder that contains many documents, then you can make queries against that collection to filter out a set of documents that you need for your front end UI. When you create a collection, you give it a name, which is usually plural. And in our case, it will store all of our user data. Now a unique thing about Fauna is that you'll also notice an option for history. It retains all of the changes that happen to a document over time. When you write to the database, Fauna never actually changes a stored document. Instead, it creates a copy of the original with the changes, then archives the original document to the history. That's extremely useful when working with time series data and also for time traveling through any changes to your data. You also have a TTL or time to live option, which can automatically delete ephemeral data that you no longer need. Now that we have our user's collection, let's go ahead and add a document to it. A document is represented as a plain JavaScript object. The data you save here does not need to follow a rigid structure. However, when you query multiple documents from a collection, it's based on the keys in this object. So if we want to match all of the users with a certain name or email address, we'll want to use the same key name in every document. Go ahead and click save, and now you should see that document in the collection. What you'll notice is that it's automatically assigned a unique ID to the document. Now if we expand the document, you can see in addition to our custom data, we also have a ref property that points to the user's collection along with that unique ID. The reference is very important because, eventually, we'll use it to join data together from multiple collections. In our case, for example, we could save a reference to this user on a tweet document so we know who a tweet belongs to, which is very similar to a foreign key in an SQL database. At this point, I'm going to add a few more users to the database, and now we need to think about how we want to access this data. There are multiple native APIs you can use to access data and Fauna. The first one that you might be familiar with is GraphQL. That's not the API we'll be using in this video. However, if you're familiar with GraphQL, you can actually upload a schema to Fauna and it will automatically create the collections and indexes required to retrieve your data based on that schema. It's really powerful stuff, but I think to really understand Fauna, you should learn its custom query language called FQL. You can execute FQL right here on the console, or you can install FaunaShell on your local system to execute it from the command line. And a little bit later, we'll learn how to use it in Node. Js. SQL is a functional language and is very intuitive and flexible, but there is a lot to learn. And I recommend keeping the SQL cheat sheet nearby. We'll look at about 10 of the most common functions, but just keep in mind that SQL can do a lot more than I present in this video. One of the first functions you'll wanna know is get, which retrieves a single document based on a reference. Get is just a function that takes a reference as an argument. We make a reference with the ref function, which takes a collection and a document ID as its arguments. If we then execute the query, we get the document data back as a result. And, as an added bonus, you'll notice if we hover over the information icon, it will tell us exactly how many bytes were transferred and a bunch of other useful information. Now, reading a single document is very easy when you have the ID, but in the real world, the document ID might not be readily available. And that brings us to our next big topic, Indexes. An index provides a way for you to define how to query documents from a collection. For example, we might want to fetch To user based on their email address or username instead of the actual document ID. A collection can have millions of documents, so an index provides a way to create a lookup table to quickly retrieve documents based on their actual internal data. 1st, we'll give our index a name, which in our case will be users by name. From there, we can specify 1 or more terms, which is a field on the document itself that can be searched. In our case, every user document has a name and we want to be able to fetch a user by the name. By default, the index will only return the document reference. But, another cool thing about Fauna is that you can tell the database which values from the document you want to return. In other words, you search a document by the username and then return the email address or whatever other data you want for the UI. That's an extremely useful little feature and we'll put it to use later in the video. Now, let's go back to the shell and we'll see how we can read a document with this index. Inside of git, we'll use the match function to search across an index. It takes the index as its first argument and then an array of search terms as the second argument. In this case, we just have the username which we can add as the second argument. And go ahead and execute the query, and you should get that same document back as the result. Now that we've explored the Fonta dashboard a little bit, we're going to switch gears into an actual Node JS application. Our goal is to build a simple REST API with Express that enables us to read and write to the database with our own custom code by making HTTP requests. You can follow along at this point by opening your IDE to an empty directory. You'll need to have Node JS installed on your system, and I'd also recommend installing the Fauna v s code extension. It allows you to see all of your collections and indexes right here in Versus Code, which is much easier than going back and forth to the dashboard. From this empty directory, we'll initialize a new npm project by running npm init with the y flag. That will give us a package JSON and then we can install FaunaDB and Express. From there, I'll create a source directory and add an index dotjs file to it, which is where we'll write all of our source code. Inside this file, we'll first require express, which will serve all of our API endpoints. And to interact with the database, we'll require FaunaDB and initialize the FaunaDB client. The client will connect your source code to the actual database in the cloud. And to do that, it requires a secret key, so let's head back to the Fauna dashboard. Board. Find the security tab, then create a new key to authenticate your server. By default, it gives you the choice between an admin and a server key. For our use case, we just need a server key. However, I would like to point out that you can implement fine grain access control right here from the Fauna dashboard. That makes it easy to follow the principle of least privilege where you only grant access to the bare minimum set of operations that are actually needed on the server. In any case, go ahead and copy the server key and then paste it into the Fonta DB client. The next thing we'll do in this file is start up our express server by calling app listen on port 5000. Now if you open the command line and run node pointed to your source directory, It will start up the server. And keep in mind that you'll need to restart it anytime the code changes. If that's too annoying for you, then check out nodemon to automatically reload anytime there's a change. Now, if you remember earlier, I mentioned that SQL is a functional language and we can import those functions and use them in JavaScript from the FaunaDB query namespace. As you can see, I've imported 10 different functions here and you don't need to know what they do at this point. The only important thing to know is that we use these functions to interact with the database. Now let's go ahead and set up our 1st API endpoint to read an individual tweet. We'll use express to set up a get endpoint that points to a tweet with its ID in the URL. Then for the callback, we'll set up an async function because any query you make to Fauna will return a promise. For this endpoint, we simply want to read a single document like we did earlier from the shell in the Fauna dashboard. Then we'll use the document itself as the response. We can make a request to Fauna for a document by awaiting a client query. Query takes an SQL expression as its argument. And remember, it's a functional language, so what you end up doing here is composing multiple JavaScript functions together. Conceptually, it's very similar to component composition in a UI framework like React. We'll start with the get function to read a single document, Then we use the ref function to make a reference to the document that we want. Ref takes 2 arguments. 1 is the collection that we want to read from, And the second is the document ID, which we'll get from the request parameters ID in the URL. And that's basically all there is to it. The promise will resolve with the actual document data, which we then send back as the response. One thing we're not doing here though is catching errors, but that would be a good idea. You can wrap the code in a try catch block, or you could simply chain the catch method to the other end of the promise. Now let's go ahead and test it out. At this point, we don't have any tweets in the database, So let's go back to Fauna and create a new collection for tweets, and then we'll add a document to it with the text of hello, world. Once created, go ahead and copy the document ID. Now at this point, we need to make a request to the URL. In my case, I'm using an HTTP client known as Insomnia. However, you could just use curl from the command line or a Versus Code extension to make these requests. In any case, what we need to do is make a get request to local host 5000/tweet followed by the tweet ID. When we send it, we should get the document back including the document data with the text of hello, world. Now that we know our API is working, we're going to look at some more complex examples of relational data. In this app, a user can have many tweets. But how do we connect a user document to a tweet document? Well, first, we need a way to create a tweet. And to handle that, we'll create a post endpoint that points to the tweet URL, and then we'll start with the same async function setup that we used in the previous endpoint. Creating a document is really easy. We just use the create function, point to the collection we want, and then pass it whatever custom data we want to save there. When we construct the data object, we can use regular JavaScript values or we can use SQL functions to get data from the database. In this case, we want the user field to be a reference to another user document in Fauna. There are many possible ways to do this, but one way is to use the select function, which will select a specific value from a document, which in this case is the reference. Now at this point, we might assume we only have the username, In which case, we can use our index, users by name, to get the corresponding user document reference. So the main takeaway here is that you can read 1 or more documents when performing some kind of other operation like a write to the database. And that allows you to model relational data in a way that's very similar to an SQL database with foreign keys. And it's also worth noting that Fauna is 100% ACID compliant, which means when you run this database transaction, it'll be globally consistent. Or, in other words, all future reads will reflect the value of the write, even when distributed across thousands of users around the world. If we go back to our HTTP client, We can make a post request to local host 5000/ tweet. Then we should get the newly created tweet back as the response. And And if you go to the Fauna dashboard, you should see it created in the user's collection there as well. Now that we have multiple tweets in the database, let's create an endpoint that can retrieve or query multiple tweets based on a username. Before we can make that query, we'll need an index. So let's go back to the Fauna dashboard and create a new index called tweets by user. The field we want to index here is the user reference to give us all the tweets owned by a user. And because we already have the user reference, we don't really need to have that returned on every single document. We can tell Fauna to only return the tweet text by setting it as a value. That way, we're only returning the actual data that we need for the UI. When we make this query, it's very similar to reading a single document, but instead of git, we use the paginate function. The difference here is that git returns the first match whereas paginate will return a set of documents that match that query. We then point to the index and then use select to grab the reference to the user. Now there is one thing that is bothering me at this point. We have some code duplication going on in our code base. Notice we're using the same exact select code for this query as we are in the previous endpoint. And getting a user is something we'll do often, so it's only going to get worse as we move forward. And that brings us to yet another awesome feature in Fauna called functions. Go ahead and copy the duplicated code and then head over to the Fauna dashboard and find the functions tab. A function allows you to Strack some SQL code so it can be used on any server or any platform. We'll give our function a name of get user and then apply it to the server role. Then in the function body, we have a query followed by a Lambda function. If you're not familiar with the Lambda function, just think of it like an anonymous arrow function in JavaScript. The value of x is something we pass into the function, then in the function body, we'll add our duplicated code. Instead of the hard coded username, we'll add a variable that points to x. And then we'll actually change the name of x to user just to make our code a little more readable. Now we can go back into our node app and reference this function. We'll need to import call and function. And And when you import function, you want to rename it something else using a colon because it collides with the built in function in JavaScript. Next, Let's find the duplicated lines of code that we want to replace. Now we can call the function by its name, get user, and then pass in whatever custom argument we want here, and it will be executed by Fonta remotely. So if you ever need to update this code, it gets updated throughout your entire code base atomically. The bottom line here is that functions provide an awesome way to keep your concise and maintainable. What we created is a one to many relationship where a user has many tweets, and a tweet belongs to a user. What we're going to look at next is the relationship between users, where a user can follow another user and or be followed by that user. Or in other words, a user can have and belong to many different relationships. It's your typical social graph data model. 1st, we'll go to the Fauna dashboard and create a new collection for relationships. Each document in this collection will contain a follower and a whose values are user document references. You can think of this document as an edge in a graph that connects 2 user accounts together, a one way graph where the follower points to the followee. Back in our code, we'll set up a new relationship endpoint That creates the relationship document. It creates a document just like we did for a tweet. The only difference is that we point to the relationship's collection. In the data object, the follower and the followee are just user references, which we can get by calling our get user function that we created previously. For now, we'll just hard code a couple of usernames in here to show that Bob follows Fireship. We can now go ahead and make a post request to the relationship endpoint and we should get a new document back that has a follower and a with a user reference on it. Now that we can establish a relationship, I want to show you how we can get all of the accounts that are followed by a given user. And not just the accounts, but also the tweets that are owned by those accounts so we can show the end user a feed of tweets from the people that they follow. The first step, of course, will be to create a new index, which will give a name of followers by followee. It will take the followee's user reference then return all the accounts that that user is following. From there, we'll go back to our code and create a new get endpoint for feed. We'll again use the paginate function in the query, but this time, instead of retrieving a single index, we're going to join 2 indexes together. The join function takes 2 arguments. The first one is the initial thing that you want to query, which in our case is all the followed users, which we can get by pointing to our recently created index and then a specific username like Bob. That will give us all of the user references that are followed by Bob. We can then join all the tweets from those users by using the index tweets by user as the second argument. If we go ahead and make that request, You can see that we now get the text from multiple tweets back from that index, and there's a lot more we could do with joins here. Instead of returning the entire index, we could use a Lambda function to filter and sort the results with our own custom logic. But, I think we'll save that for a future video. I'm gonna go ahead and wrap things up there. Fauna is a truly awesome database and the more I use it, the more I like it. If I were starting a new project today, Fauna would definitely be at the top of my list for the tech stack. If you wanna see more videos on this topic, let me know in the comments. Consider supporting my work with a GitHub sponsorship, or by becoming a pro member at Fireship IO. Thanks for watching, and I will see you in the next one.
When
when
you
you
build
build
an
an
app,
app
one
one
of
of
the
the
main
main
pain
pain
points
points
that
that
you'll
you'll
face
face
is
is
your
your
database.
database
You
you
often
often
hear
hear
developers
developers
debate
debate
the
the
merits
merits
of
of
SQL
sql
versus
versus
NoSQL.
nosql
On
on
one
one
hand,
hand
you
you
have
have
safety,
safety
security,
security
and
and
consistency.
consistency
And,
and
on
on
the
the
other,
other
you
you
have
have
flexibility,
flexibility
scalability,
scalability
and
and
productivity.
productivity
But,
but
what
what
if
if
there's
there's
a
a
database
database
that
that
could
could
put
put
an
an
end
end
to
to
this
this
debate
debate
once
once
and
and
for
for
all?
all
Fauna
fauna
DB
db
is
is
the
the
cloud
cloud
database
database
that
that
I've
i've
always
always
dreamed
dreamed
of.
of
It's
it's
entirely
entirely
serverless,
serverless
so
so
we
we
don't
don't
have
have
to
to
provision
provision
anything
anything
and
and
we
we
only
only
pay
pay
for
for
what
what
we
we
actually
actually
use
use
beyond
beyond
the
the
free
free
tier.
tier
It's
it's
as
as
easy
easy
to
to
use
use
as
as
a
a
document
document
database.
database
And,
and
you
you
can
can
manage
manage
your
your
data
data
from
from
its
its
web
web
interface
interface
or
or
the
the
command
command
line.
line
It's
it's
extremely
extremely
fast
fast
and
and
scales
scales
infinitely
infinitely
in
in
the
the
cloud
cloud
and
and
is
is
the
the
1st
1st
database
database
in
in
the
the
world
world
to
to
implement
implement
a
a
Calvin
calvin
model
model
for
for
partition
partition
database
database
systems.
systems
Most
most
importantly
importantly
though,
though
is
is
its
its
ability
ability
to
to
handle
handle
complex
complex
data
data
modeling
modeling
use
use
cases,
cases
like
like
the
the
ones
ones
you
you
would
would
find
find
in
in
a
a
relational,
relational
no
no
graph
graph
or
or
time
time
series
series
database.
database
Over
over
the
the
next
next
few
few
minutes,
minutes
you'll
you'll
learn
learn
everything
everything
you
you
need
need
to
to
know
know
to
to
get
get
up
up
and
and
running
running
with
with
FaunaDB.
faunadb
We'll
we'll
use
use
it
it
to
to
model
model
the
the
data
data
relationships
relationships
tips
tips
that
that
you
you
would
would
find
find
on
on
Twitter.
twitter
A
a
user
user
has
has
many
many
tweets,
tweets
users
users
can
can
follow
follow
each
each
other,
other
and
and
retrieve
retrieve
a
a
feed
feed
of
of
tweets
tweets
from
from
all
all
the
the
users
users
that
that
they
they
follow.
follow
We'll
we'll
write
write
our
our
code
code
in
in
Node.
node
Js,
js
and
and
by
by
the
the
end
end
of
of
the
the
video,
video
you'll
you'll
have
have
an
an
API
api
that
that
you
you
can
can
use
use
to
to
connect
connect
to
to
your
your
front
front
end
end
application.
application
If
if
you're
you're
new
new
here,
here
like
like
and
and
subscribe
subscribe
and
and
check
check
out
out
the
the
full
full
write
write
up
up
on
on
FireShip
fireship
IO.
io
To
to
follow
follow
along
along
today,
today
the
the
first
first
thing
thing
you'll
you'll
need
need
is
is
a
a
free
free
Fauna
fauna
account.
account
Once
once
logged
logged
in,
in
you'll
you'll
see
see
the
the
Fauna
fauna
dashboard.
dashboard
At
at
this
this
point,
point
you
you
won't
won't
have
have
a
a
database,
database
so
so
go
go
ahead
ahead
and
and
click
click
the
the
button
button
to
to
create
create
a
a
new
new
one.
one
This
this
is
is
what's
what's
known
known
as
as
a
a
top
top
level
level
database,
database
and
and
an
an
awesome
awesome
thing
thing
about
about
Fauna
fauna
is
is
that
that
it
it
supports
supports
multi
multi
tenancy.
tenancy
It's
it's
beyond
beyond
the
the
scope
scope
of
of
this
this
video,
video
but
but
a
a
cool
cool
feature
feature
you
you
should
should
know
know
about.
about
A
a
database
database
can
can
have
have
an
an
unlimited
unlimited
number
number
of
of
child
child
databases,
databases
allowing
allowing
you
you
to
to
scope
scope
data
data
and
and
privileges
privileges
to
to
a
a
specific
specific
organization
organization
or
or
team.
team
In
in
most
most
cases,
cases
though,
though
you'll
you'll
just
just
need
need
one
one
single
single
database
database
for
for
your
your
entire
entire
per
per
application.
application
Now
now
that
that
we
we
have
have
a
a
database,
database
we'll
we'll
create
create
a
a
collection.
collection
A
a
collection
collection
is
is
like
like
an
an
SQL
sql
table
table
and
and
works
works
very
very
similar
similar
to
to
other
other
document
document
oriented
oriented
databases
databases
like
like
MongoDB
mongodb
or
or
Firestore.
firestore
A
a
collection
collection
is
is
kind
kind
of
of
like
like
a
a
folder
folder
that
that
contains
contains
many
many
documents,
documents
then
then
you
you
can
can
make
make
queries
queries
against
against
that
that
collection
collection
to
to
filter
filter
out
out
a
a
set
set
of
of
documents
documents
that
that
you
you
need
need
for
for
your
your
front
front
end
end
UI.
ui
When
when
you
you
create
create
a
a
collection,
collection
you
you
give
give
it
it
a
a
name,
name
which
which
is
is
usually
usually
plural.
plural
And
and
in
in
our
our
case,
case
it
it
will
will
store
store
all
all
of
of
our
our
user
user
data.
data
Now
now
a
a
unique
unique
thing
thing
about
about
Fauna
fauna
is
is
that
that
you'll
you'll
also
also
notice
notice
an
an
option
option
for
for
history.
history
It
it
retains
retains
all
all
of
of
the
the
changes
changes
that
that
happen
happen
to
to
a
a
document
document
over
over
time.
time
When
when
you
you
write
write
to
to
the
the
database,
database
Fauna
fauna
never
never
actually
actually
changes
changes
a
a
stored
stored
document.
document
Instead,
instead
it
it
creates
creates
a
a
copy
copy
of
of
the
the
original
original
with
with
the
the
changes,
changes
then
then
archives
archives
the
the
original
original
document
document
to
to
the
the
history.
history
That's
that's
extremely
extremely
useful
useful
when
when
working
working
with
with
time
time
series
series
data
data
and
and
also
also
for
for
time
time
traveling
traveling
through
through
any
any
changes
changes
to
to
your
your
data.
data
You
you
also
also
have
have
a
a
TTL
ttl
or
or
time
time
to
to
live
live
option,
option
which
which
can
can
automatically
automatically
delete
delete
ephemeral
ephemeral
data
data
that
that
you
you
no
no
longer
longer
need.
need
Now
now
that
that
we
we
have
have
our
our
user's
user's
collection,
collection
let's
let's
go
go
ahead
ahead
and
and
add
add
a
a
document
document
to
to
it.
it
A
a
document
document
is
is
represented
represented
as
as
a
a
plain
plain
JavaScript
javascript
object.
object
The
the
data
data
you
you
save
save
here
here
does
does
not
not
need
need
to
to
follow
follow
a
a
rigid
rigid
structure.
structure
However,
however
when
when
you
you
query
query
multiple
multiple
documents
documents
from
from
a
a
collection,
collection
it's
it's
based
based
on
on
the
the
keys
keys
in
in
this
this
object.
object
So
so
if
if
we
we
want
want
to
to
match
match
all
all
of
of
the
the
users
users
with
with
a
a
certain
certain
name
name
or
or
email
email
address,
address
we'll
we'll
want
want
to
to
use
use
the
the
same
same
key
key
name
name
in
in
every
every
document.
document
Go
go
ahead
ahead
and
and
click
click
save,
save
and
and
now
now
you
you
should
should
see
see
that
that
document
document
in
in
the
the
collection.
collection
What
what
you'll
you'll
notice
notice
is
is
that
that
it's
it's
automatically
automatically
assigned
assigned
a
a
unique
unique
ID
id
to
to
the
the
document.
document
Now
now
if
if
we
we
expand
expand
the
the
document,
document
you
you
can
can
see
see
in
in
addition
addition
to
to
our
our
custom
custom
data,
data
we
we
also
also
have
have
a
a
ref
ref
property
property
that
that
points
points
to
to
the
the
user's
user's
collection
collection
along
along
with
with
that
that
unique
unique
ID.
id
The
the
reference
reference
is
is
very
very
important
important
because,
because
eventually,
eventually
we'll
we'll
use
use
it
it
to
to
join
join
data
data
together
together
from
from
multiple
multiple
collections.
collections
In
in
our
our
case,
case
for
for
example,
example
we
we
could
could
save
save
a
a
reference
reference
to
to
this
this
user
user
on
on
a
a
tweet
tweet
document
document
so
so
we
we
know
know
who
who
a
a
tweet
tweet
belongs
belongs
to,
to
which
which
is
is
very
very
similar
similar
to
to
a
a
foreign
foreign
key
key
in
in
an
an
SQL
sql
database.
database
At
at
this
this
point,
point
I'm
i'm
going
going
to
to
add
add
a
a
few
few
more
more
users
users
to
to
the
the
database,
database
and
and
now
now
we
we
need
need
to
to
think
think
about
about
how
how
we
we
want
want
to
to
access
access
this
this
data.
data
There
there
are
are
multiple
multiple
native
native
APIs
apis
you
you
can
can
use
use
to
to
access
access
data
data
and
and
Fauna.
fauna
The
the
first
first
one
one
that
that
you
you
might
might
be
be
familiar
familiar
with
with
is
is
GraphQL.
graphql
That's
that's
not
not
the
the
API
api
we'll
we'll
be
be
using
using
in
in
this
this
video.
video
However,
however
if
if
you're
you're
familiar
familiar
with
with
GraphQL,
graphql
you
you
can
can
actually
actually
upload
upload
a
a
schema
schema
to
to
Fauna
fauna
and
and
it
it
will
will
automatically
automatically
create
create
the
the
collections
collections
and
and
indexes
indexes
required
required
to
to
retrieve
retrieve
your
your
data
data
based
based
on
on
that
that
schema.
schema
It's
it's
really
really
powerful
powerful
stuff,
stuff
but
but
I
i
think
think
to
to
really
really
understand
understand
Fauna,
fauna
you
you
should
should
learn
learn
its
its
custom
custom
query
query
language
language
called
called
FQL.
fql
You
you
can
can
execute
execute
FQL
fql
right
right
here
here
on
on
the
the
console,
console
or
or
you
you
can
can
install
install
FaunaShell
faunashell
on
on
your
your
local
local
system
system
to
to
execute
execute
it
it
from
from
the
the
command
command
line.
line
And
and
a
a
little
little
bit
bit
later,
later
we'll
we'll
learn
learn
how
how
to
to
use
use
it
it
in
in
Node.
node
Js.
js
SQL
sql
is
is
a
a
functional
functional
language
language
and
and
is
is
very
very
intuitive
intuitive
and
and
flexible,
flexible
but
but
there
there
is
is
a
a
lot
lot
to
to
learn.
learn
And
and
I
i
recommend
recommend
keeping
keeping
the
the
SQL
sql
cheat
cheat
sheet
sheet
nearby.
nearby
We'll
we'll
look
look
at
at
about
about
10
10
of
of
the
the
most
most
common
common
functions,
functions
but
but
just
just
keep
keep
in
in
mind
mind
that
that
SQL
sql
can
can
do
do
a
a
lot
lot
more
more
than
than
I
i
present
present
in
in
this
this
video.
video
One
one
of
of
the
the
first
first
functions
functions
you'll
you'll
wanna
wanna
know
know
is
is
get,
get
which
which
retrieves
retrieves
a
a
single
single
document
document
based
based
on
on
a
a
reference.
reference
Get
get
is
is
just
just
a
a
function
function
that
that
takes
takes
a
a
reference
reference
as
as
an
an
argument.
argument
We
we
make
make
a
a
reference
reference
with
with
the
the
ref
ref
function,
function
which
which
takes
takes
a
a
collection
collection
and
and
a
a
document
document
ID
id
as
as
its
its
arguments.
arguments
If
if
we
we
then
then
execute
execute
the
the
query,
query
we
we
get
get
the
the
document
document
data
data
back
back
as
as
a
a
result.
result
And,
and
as
as
an
an
added
added
bonus,
bonus
you'll
you'll
notice
notice
if
if
we
we
hover
hover
over
over
the
the
information
information
icon,
icon
it
it
will
will
tell
tell
us
us
exactly
exactly
how
how
many
many
bytes
bytes
were
were
transferred
transferred
and
and
a
a
bunch
bunch
of
of
other
other
useful
useful
information.
information
Now,
now
reading
reading
a
a
single
single
document
document
is
is
very
very
easy
easy
when
when
you
you
have
have
the
the
ID,
id
but
but
in
in
the
the
real
real
world,
world
the
the
document
document
ID
id
might
might
not
not
be
be
readily
readily
available.
available
And
and
that
that
brings
brings
us
us
to
to
our
our
next
next
big
big
topic,
topic
Indexes.
indexes
An
an
index
index
provides
provides
a
a
way
way
for
for
you
you
to
to
define
define
how
how
to
to
query
query
documents
documents
from
from
a
a
collection.
collection
For
for
example,
example
we
we
might
might
want
want
to
to
fetch
fetch
To
to
user
user
based
based
on
on
their
their
email
email
address
address
or
or
username
username
instead
instead
of
of
the
the
actual
actual
document
document
ID.
id
A
a
collection
collection
can
can
have
have
millions
millions
of
of
documents,
documents
so
so
an
an
index
index
provides
provides
a
a
way
way
to
to
create
create
a
a
lookup
lookup
table
table
to
to
quickly
quickly
retrieve
retrieve
documents
documents
based
based
on
on
their
their
actual
actual
internal
internal
data.
data
1st,
1st
we'll
we'll
give
give
our
our
index
index
a
a
name,
name
which
which
in
in
our
our
case
case
will
will
be
be
users
users
by
by
name.
name
From
from
there,
there
we
we
can
can
specify
specify
1
1
or
or
more
more
terms,
terms
which
which
is
is
a
a
field
field
on
on
the
the
document
document
itself
itself
that
that
can
can
be
be
searched.
searched
In
in
our
our
case,
case
every
every
user
user
document
document
has
has
a
a
name
name
and
and
we
we
want
want
to
to
be
be
able
able
to
to
fetch
fetch
a
a
user
user
by
by
the
the
name.
name
By
by
default,
default
the
the
index
index
will
will
only
only
return
return
the
the
document
document
reference.
reference
But,
but
another
another
cool
cool
thing
thing
about
about
Fauna
fauna
is
is
that
that
you
you
can
can
tell
tell
the
the
database
database
which
which
values
values
from
from
the
the
document
document
you
you
want
want
to
to
return.
return
In
in
other
other
words,
words
you
you
search
search
a
a
document
document
by
by
the
the
username
username
and
and
then
then
return
return
the
the
email
email
address
address
or
or
whatever
whatever
other
other
data
data
you
you
want
want
for
for
the
the
UI.
ui
That's
that's
an
an
extremely
extremely
useful
useful
little
little
feature
feature
and
and
we'll
we'll
put
put
it
it
to
to
use
use
later
later
in
in
the
the
video.
video
Now,
now
let's
let's
go
go
back
back
to
to
the
the
shell
shell
and
and
we'll
we'll
see
see
how
how
we
we
can
can
read
read
a
a
document
document
with
with
this
this
index.
index
Inside
inside
of
of
git,
git
we'll
we'll
use
use
the
the
match
match
function
function
to
to
search
search
across
across
an
an
index.
index
It
it
takes
takes
the
the
index
index
as
as
its
its
first
first
argument
argument
and
and
then
then
an
an
array
array
of
of
search
search
terms
terms
as
as
the
the
second
second
argument.
argument
In
in
this
this
case,
case
we
we
just
just
have
have
the
the
username
username
which
which
we
we
can
can
add
add
as
as
the
the
second
second
argument.
argument
And
and
go
go
ahead
ahead
and
and
execute
execute
the
the
query,
query
and
and
you
you
should
should
get
get
that
that
same
same
document
document
back
back
as
as
the
the
result.
result
Now
now
that
that
we've
we've
explored
explored
the
the
Fonta
fonta
dashboard
dashboard
a
a
little
little
bit,
bit
we're
we're
going
going
to
to
switch
switch
gears
gears
into
into
an
an
actual
actual
Node
node
JS
js
application.
application
Our
our
goal
goal
is
is
to
to
build
build
a
a
simple
simple
REST
rest
API
api
with
with
Express
express
that
that
enables
enables
us
us
to
to
read
read
and
and
write
write
to
to
the
the
database
database
with
with
our
our
own
own
custom
custom
code
code
by
by
making
making
HTTP
http
requests.
requests
You
you
can
can
follow
follow
along
along
at
at
this
this
point
point
by
by
opening
opening
your
your
IDE
ide
to
to
an
an
empty
empty
directory.
directory
You'll
you'll
need
need
to
to
have
have
Node
node
JS
js
installed
installed
on
on
your
your
system,
system
and
and
I'd
i'd
also
also
recommend
recommend
installing
installing
the
the
Fauna
fauna
v
v
s
s
code
code
extension.
extension
It
it
allows
allows
you
you
to
to
see
see
all
all
of
of
your
your
collections
collections
and
and
indexes
indexes
right
right
here
here
in
in
Versus
versus
Code,
code
which
which
is
is
much
much
easier
easier
than
than
going
going
back
back
and
and
forth
forth
to
to
the
the
dashboard.
dashboard
From
from
this
this
empty
empty
directory,
directory
we'll
we'll
initialize
initialize
a
a
new
new
npm
npm
project
project
by
by
running
running
npm
npm
init
init
with
with
the
the
y
y
flag.
flag
That
that
will
will
give
give
us
us
a
a
package
package
JSON
json
and
and
then
then
we
we
can
can
install
install
FaunaDB
faunadb
and
and
Express.
express
From
from
there,
there
I'll
i'll
create
create
a
a
source
source
directory
directory
and
and
add
add
an
an
index
index
dotjs
dotjs
file
file
to
to
it,
it
which
which
is
is
where
where
we'll
we'll
write
write
all
all
of
of
our
our
source
source
code.
code
Inside
inside
this
this
file,
file
we'll
we'll
first
first
require
require
express,
express
which
which
will
will
serve
serve
all
all
of
of
our
our
API
api
endpoints.
endpoints
And
and
to
to
interact
interact
with
with
the
the
database,
database
we'll
we'll
require
require
FaunaDB
faunadb
and
and
initialize
initialize
the
the
FaunaDB
faunadb
client.
client
The
the
client
client
will
will
connect
connect
your
your
source
source
code
code
to
to
the
the
actual
actual
database
database
in
in
the
the
cloud.
cloud
And
and
to
to
do
do
that,
that
it
it
requires
requires
a
a
secret
secret
key,
key
so
so
let's
let's
head
head
back
back
to
to
the
the
Fauna
fauna
dashboard.
dashboard
Board.
board
Find
find
the
the
security
security
tab,
tab
then
then
create
create
a
a
new
new
key
key
to
to
authenticate
authenticate
your
your
server.
server
By
by
default,
default
it
it
gives
gives
you
you
the
the
choice
choice
between
between
an
an
admin
admin
and
and
a
a
server
server
key.
key
For
for
our
our
use
use
case,
case
we
we
just
just
need
need
a
a
server
server
key.
key
However,
however
I
i
would
would
like
like
to
to
point
point
out
out
that
that
you
you
can
can
implement
implement
fine
fine
grain
grain
access
access
control
control
right
right
here
here
from
from
the
the
Fauna
fauna
dashboard.
dashboard
That
that
makes
makes
it
it
easy
easy
to
to
follow
follow
the
the
principle
principle
of
of
least
least
privilege
privilege
where
where
you
you
only
only
grant
grant
access
access
to
to
the
the
bare
bare
minimum
minimum
set
set
of
of
operations
operations
that
that
are
are
actually
actually
needed
needed
on
on
the
the
server.
server
In
in
any
any
case,
case
go
go
ahead
ahead
and
and
copy
copy
the
the
server
server
key
key
and
and
then
then
paste
paste
it
it
into
into
the
the
Fonta
fonta
DB
db
client.
client
The
the
next
next
thing
thing
we'll
we'll
do
do
in
in
this
this
file
file
is
is
start
start
up
up
our
our
express
express
server
server
by
by
calling
calling
app
app
listen
listen
on
on
port
port
5000.
5000
Now
now
if
if
you
you
open
open
the
the
command
command
line
line
and
and
run
run
node
node
pointed
pointed
to
to
your
your
source
source
directory,
directory
It
it
will
will
start
start
up
up
the
the
server.
server
And
and
keep
keep
in
in
mind
mind
that
that
you'll
you'll
need
need
to
to
restart
restart
it
it
anytime
anytime
the
the
code
code
changes.
changes
If
if
that's
that's
too
too
annoying
annoying
for
for
you,
you
then
then
check
check
out
out
nodemon
nodemon
to
to
automatically
automatically
reload
reload
anytime
anytime
there's
there's
a
a
change.
change
Now,
now
if
if
you
you
remember
remember
earlier,
earlier
I
i
mentioned
mentioned
that
that
SQL
sql
is
is
a
a
functional
functional
language
language
and
and
we
we
can
can
import
import
those
those
functions
functions
and
and
use
use
them
them
in
in
JavaScript
javascript
from
from
the
the
FaunaDB
faunadb
query
query
namespace.
namespace
As
as
you
you
can
can
see,
see
I've
i've
imported
imported
10
10
different
different
functions
functions
here
here
and
and
you
you
don't
don't
need
need
to
to
know
know
what
what
they
they
do
do
at
at
this
this
point.
point
The
the
only
only
important
important
thing
thing
to
to
know
know
is
is
that
that
we
we
use
use
these
these
functions
functions
to
to
interact
interact
with
with
the
the
database.
database
Now
now
let's
let's
go
go
ahead
ahead
and
and
set
set
up
up
our
our
1st
1st
API
api
endpoint
endpoint
to
to
read
read
an
an
individual
individual
tweet.
tweet
We'll
we'll
use
use
express
express
to
to
set
set
up
up
a
a
get
get
endpoint
endpoint
that
that
points
points
to
to
a
a
tweet
tweet
with
with
its
its
ID
id
in
in
the
the
URL.
url
Then
then
for
for
the
the
callback,
callback
we'll
we'll
set
set
up
up
an
an
async
async
function
function
because
because
any
any
query
query
you
you
make
make
to
to
Fauna
fauna
will
will
return
return
a
a
promise.
promise
For
for
this
this
endpoint,
endpoint
we
we
simply
simply
want
want
to
to
read
read
a
a
single
single
document
document
like
like
we
we
did
did
earlier
earlier
from
from
the
the
shell
shell
in
in
the
the
Fauna
fauna
dashboard.
dashboard
Then
then
we'll
we'll
use
use
the
the
document
document
itself
itself
as
as
the
the
response.
response
We
we
can
can
make
make
a
a
request
request
to
to
Fauna
fauna
for
for
a
a
document
document
by
by
awaiting
awaiting
a
a
client
client
query.
query
Query
query
takes
takes
an
an
SQL
sql
expression
expression
as
as
its
its
argument.
argument
And
and
remember,
remember
it's
it's
a
a
functional
functional
language,
language
so
so
what
what
you
you
end
end
up
up
doing
doing
here
here
is
is
composing
composing
multiple
multiple
JavaScript
javascript
functions
functions
together.
together
Conceptually,
conceptually
it's
it's
very
very
similar
similar
to
to
component
component
composition
composition
in
in
a
a
UI
ui
framework
framework
like
like
React.
react
We'll
we'll
start
start
with
with
the
the
get
get
function
function
to
to
read
read
a
a
single
single
document,
document
Then
then
we
we
use
use
the
the
ref
ref
function
function
to
to
make
make
a
a
reference
reference
to
to
the
the
document
document
that
that
we
we
want.
want
Ref
ref
takes
takes
2
2
arguments.
arguments
1
1
is
is
the
the
collection
collection
that
that
we
we
want
want
to
to
read
read
from,
from
And
and
the
the
second
second
is
is
the
the
document
document
ID,
id
which
which
we'll
we'll
get
get
from
from
the
the
request
request
parameters
parameters
ID
id
in
in
the
the
URL.
url
And
and
that's
that's
basically
basically
all
all
there
there
is
is
to
to
it.
it
The
the
promise
promise
will
will
resolve
resolve
with
with
the
the
actual
actual
document
document
data,
data
which
which
we
we
then
then
send
send
back
back
as
as
the
the
response.
response
One
one
thing
thing
we're
we're
not
not
doing
doing
here
here
though
though
is
is
catching
catching
errors,
errors
but
but
that
that
would
would
be
be
a
a
good
good
idea.
idea
You
you
can
can
wrap
wrap
the
the
code
code
in
in
a
a
try
try
catch
catch
block,
block
or
or
you
you
could
could
simply
simply
chain
chain
the
the
catch
catch
method
method
to
to
the
the
other
other
end
end
of
of
the
the
promise.
promise
Now
now
let's
let's
go
go
ahead
ahead
and
and
test
test
it
it
out.
out
At
at
this
this
point,
point
we
we
don't
don't
have
have
any
any
tweets
tweets
in
in
the
the
database,
database
So
so
let's
let's
go
go
back
back
to
to
Fauna
fauna
and
and
create
create
a
a
new
new
collection
collection
for
for
tweets,
tweets
and
and
then
then
we'll
we'll
add
add
a
a
document
document
to
to
it
it
with
with
the
the
text
text
of
of
hello,
hello
world.
world
Once
once
created,
created
go
go
ahead
ahead
and
and
copy
copy
the
the
document
document
ID.
id
Now
now
at
at
this
this
point,
point
we
we
need
need
to
to
make
make
a
a
request
request
to
to
the
the
URL.
url
In
in
my
my
case,
case
I'm
i'm
using
using
an
an
HTTP
http
client
client
known
known
as
as
Insomnia.
insomnia
However,
however
you
you
could
could
just
just
use
use
curl
curl
from
from
the
the
command
command
line
line
or
or
a
a
Versus
versus
Code
code
extension
extension
to
to
make
make
these
these
requests.
requests
In
in
any
any
case,
case
what
what
we
we
need
need
to
to
do
do
is
is
make
make
a
a
get
get
request
request
to
to
local
local
host
host
5000/tweet
5000/tweet
followed
followed
by
by
the
the
tweet
tweet
ID.
id
When
when
we
we
send
send
it,
it
we
we
should
should
get
get
the
the
document
document
back
back
including
including
the
the
document
document
data
data
with
with
the
the
text
text
of
of
hello,
hello
world.
world
Now
now
that
that
we
we
know
know
our
our
API
api
is
is
working,
working
we're
we're
going
going
to
to
look
look
at
at
some
some
more
more
complex
complex
examples
examples
of
of
relational
relational
data.
data
In
in
this
this
app,
app
a
a
user
user
can
can
have
have
many
many
tweets.
tweets
But
but
how
how
do
do
we
we
connect
connect
a
a
user
user
document
document
to
to
a
a
tweet
tweet
document?
document
Well,
well
first,
first
we
we
need
need
a
a
way
way
to
to
create
create
a
a
tweet.
tweet
And
and
to
to
handle
handle
that,
that
we'll
we'll
create
create
a
a
post
post
endpoint
endpoint
that
that
points
points
to
to
the
the
tweet
tweet
URL,
url
and
and
then
then
we'll
we'll
start
start
with
with
the
the
same
same
async
async
function
function
setup
setup
that
that
we
we
used
used
in
in
the
the
previous
previous
endpoint.
endpoint
Creating
creating
a
a
document
document
is
is
really
really
easy.
easy
We
we
just
just
use
use
the
the
create
create
function,
function
point
point
to
to
the
the
collection
collection
we
we
want,
want
and
and
then
then
pass
pass
it
it
whatever
whatever
custom
custom
data
data
we
we
want
want
to
to
save
save
there.
there
When
when
we
we
construct
construct
the
the
data
data
object,
object
we
we
can
can
use
use
regular
regular
JavaScript
javascript
values
values
or
or
we
we
can
can
use
use
SQL
sql
functions
functions
to
to
get
get
data
data
from
from
the
the
database.
database
In
in
this
this
case,
case
we
we
want
want
the
the
user
user
field
field
to
to
be
be
a
a
reference
reference
to
to
another
another
user
user
document
document
in
in
Fauna.
fauna
There
there
are
are
many
many
possible
possible
ways
ways
to
to
do
do
this,
this
but
but
one
one
way
way
is
is
to
to
use
use
the
the
select
select
function,
function
which
which
will
will
select
select
a
a
specific
specific
value
value
from
from
a
a
document,
document
which
which
in
in
this
this
case
case
is
is
the
the
reference.
reference
Now
now
at
at
this
this
point,
point
we
we
might
might
assume
assume
we
we
only
only
have
have
the
the
username,
username
In
in
which
which
case,
case
we
we
can
can
use
use
our
our
index,
index
users
users
by
by
name,
name
to
to
get
get
the
the
corresponding
corresponding
user
user
document
document
reference.
reference
So
so
the
the
main
main
takeaway
takeaway
here
here
is
is
that
that
you
you
can
can
read
read
1
1
or
or
more
more
documents
documents
when
when
performing
performing
some
some
kind
kind
of
of
other
other
operation
operation
like
like
a
a
write
write
to
to
the
the
database.
database
And
and
that
that
allows
allows
you
you
to
to
model
model
relational
relational
data
data
in
in
a
a
way
way
that's
that's
very
very
similar
similar
to
to
an
an
SQL
sql
database
database
with
with
foreign
foreign
keys.
keys
And
and
it's
it's
also
also
worth
worth
noting
noting
that
that
Fauna
fauna
is
is
100%
100%
ACID
acid
compliant,
compliant
which
which
means
means
when
when
you
you
run
run
this
this
database
database
transaction,
transaction
it'll
it'll
be
be
globally
globally
consistent.
consistent
Or,
or
in
in
other
other
words,
words
all
all
future
future
reads
reads
will
will
reflect
reflect
the
the
value
value
of
of
the
the
write,
write
even
even
when
when
distributed
distributed
across
across
thousands
thousands
of
of
users
users
around
around
the
the
world.
world
If
if
we
we
go
go
back
back
to
to
our
our
HTTP
http
client,
client
We
we
can
can
make
make
a
a
post
post
request
request
to
to
local
local
host
host
5000/
5000/
tweet.
tweet
Then
then
we
we
should
should
get
get
the
the
newly
newly
created
created
tweet
tweet
back
back
as
as
the
the
response.
response
And
and
And
and
if
if
you
you
go
go
to
to
the
the
Fauna
fauna
dashboard,
dashboard
you
you
should
should
see
see
it
it
created
created
in
in
the
the
user's
user's
collection
collection
there
there
as
as
well.
well
Now
now
that
that
we
we
have
have
multiple
multiple
tweets
tweets
in
in
the
the
database,
database
let's
let's
create
create
an
an
endpoint
endpoint
that
that
can
can
retrieve
retrieve
or
or
query
query
multiple
multiple
tweets
tweets
based
based
on
on
a
a
username.
username
Before
before
we
we
can
can
make
make
that
that
query,
query
we'll
we'll
need
need
an
an
index.
index
So
so
let's
let's
go
go
back
back
to
to
the
the
Fauna
fauna
dashboard
dashboard
and
and
create
create
a
a
new
new
index
index
called
called
tweets
tweets
by
by
user.
user
The
the
field
field
we
we
want
want
to
to
index
index
here
here
is
is
the
the
user
user
reference
reference
to
to
give
give
us
us
all
all
the
the
tweets
tweets
owned
owned
by
by
a
a
user.
user
And
and
because
because
we
we
already
already
have
have
the
the
user
user
reference,
reference
we
we
don't
don't
really
really
need
need
to
to
have
have
that
that
returned
returned
on
on
every
every
single
single
document.
document
We
we
can
can
tell
tell
Fauna
fauna
to
to
only
only
return
return
the
the
tweet
tweet
text
text
by
by
setting
setting
it
it
as
as
a
a
value.
value
That
that
way,
way
we're
we're
only
only
returning
returning
the
the
actual
actual
data
data
that
that
we
we
need
need
for
for
the
the
UI.
ui
When
when
we
we
make
make
this
this
query,
query
it's
it's
very
very
similar
similar
to
to
reading
reading
a
a
single
single
document,
document
but
but
instead
instead
of
of
git,
git
we
we
use
use
the
the
paginate
paginate
function.
function
The
the
difference
difference
here
here
is
is
that
that
git
git
returns
returns
the
the
first
first
match
match
whereas
whereas
paginate
paginate
will
will
return
return
a
a
set
set
of
of
documents
documents
that
that
match
match
that
that
query.
query
We
we
then
then
point
point
to
to
the
the
index
index
and
and
then
then
use
use
select
select
to
to
grab
grab
the
the
reference
reference
to
to
the
the
user.
user
Now
now
there
there
is
is
one
one
thing
thing
that
that
is
is
bothering
bothering
me
me
at
at
this
this
point.
point
We
we
have
have
some
some
code
code
duplication
duplication
going
going
on
on
in
in
our
our
code
code
base.
base
Notice
notice
we're
we're
using
using
the
the
same
same
exact
exact
select
select
code
code
for
for
this
this
query
query
as
as
we
we
are
are
in
in
the
the
previous
previous
endpoint.
endpoint
And
and
getting
getting
a
a
user
user
is
is
something
something
we'll
we'll
do
do
often,
often
so
so
it's
it's
only
only
going
going
to
to
get
get
worse
worse
as
as
we
we
move
move
forward.
forward
And
and
that
that
brings
brings
us
us
to
to
yet
yet
another
another
awesome
awesome
feature
feature
in
in
Fauna
fauna
called
called
functions.
functions
Go
go
ahead
ahead
and
and
copy
copy
the
the
duplicated
duplicated
code
code
and
and
then
then
head
head
over
over
to
to
the
the
Fauna
fauna
dashboard
dashboard
and
and
find
find
the
the
functions
functions
tab.
tab
A
a
function
function
allows
allows
you
you
to
to
Strack
strack
some
some
SQL
sql
code
code
so
so
it
it
can
can
be
be
used
used
on
on
any
any
server
server
or
or
any
any
platform.
platform
We'll
we'll
give
give
our
our
function
function
a
a
name
name
of
of
get
get
user
user
and
and
then
then
apply
apply
it
it
to
to
the
the
server
server
role.
role
Then
then
in
in
the
the
function
function
body,
body
we
we
have
have
a
a
query
query
followed
followed
by
by
a
a
Lambda
lambda
function.
function
If
if
you're
you're
not
not
familiar
familiar
with
with
the
the
Lambda
lambda
function,
function
just
just
think
think
of
of
it
it
like
like
an
an
anonymous
anonymous
arrow
arrow
function
function
in
in
JavaScript.
javascript
The
the
value
value
of
of
x
x
is
is
something
something
we
we
pass
pass
into
into
the
the
function,
function
then
then
in
in
the
the
function
function
body,
body
we'll
we'll
add
add
our
our
duplicated
duplicated
code.
code
Instead
instead
of
of
the
the
hard
hard
coded
coded
username,
username
we'll
we'll
add
add
a
a
variable
variable
that
that
points
points
to
to
x.
x
And
and
then
then
we'll
we'll
actually
actually
change
change
the
the
name
name
of
of
x
x
to
to
user
user
just
just
to
to
make
make
our
our
code
code
a
a
little
little
more
more
readable.
readable
Now
now
we
we
can
can
go
go
back
back
into
into
our
our
node
node
app
app
and
and
reference
reference
this
this
function.
function
We'll
we'll
need
need
to
to
import
import
call
call
and
and
function.
function
And
and
And
and
when
when
you
you
import
import
function,
function
you
you
want
want
to
to
rename
rename
it
it
something
something
else
else
using
using
a
a
colon
colon
because
because
it
it
collides
collides
with
with
the
the
built
built
in
in
function
function
in
in
JavaScript.
javascript
Next,
next
Let's
let's
find
find
the
the
duplicated
duplicated
lines
lines
of
of
code
code
that
that
we
we
want
want
to
to
replace.
replace
Now
now
we
we
can
can
call
call
the
the
function
function
by
by
its
its
name,
name
get
get
user,
user
and
and
then
then
pass
pass
in
in
whatever
whatever
custom
custom
argument
argument
we
we
want
want
here,
here
and
and
it
it
will
will
be
be
executed
executed
by
by
Fonta
fonta
remotely.
remotely
So
so
if
if
you
you
ever
ever
need
need
to
to
update
update
this
this
code,
code
it
it
gets
gets
updated
updated
throughout
throughout
your
your
entire
entire
code
code
base
base
atomically.
atomically
The
the
bottom
bottom
line
line
here
here
is
is
that
that
functions
functions
provide
provide
an
an
awesome
awesome
way
way
to
to
keep
keep
your
your
concise
concise
and
and
maintainable.
maintainable
What
what
we
we
created
created
is
is
a
a
one
one
to
to
many
many
relationship
relationship
where
where
a
a
user
user
has
has
many
many
tweets,
tweets
and
and
a
a
tweet
tweet
belongs
belongs
to
to
a
a
user.
user
What
what
we're
we're
going
going
to
to
look
look
at
at
next
next
is
is
the
the
relationship
relationship
between
between
users,
users
where
where
a
a
user
user
can
can
follow
follow
another
another
user
user
and
and
or
or
be
be
followed
followed
by
by
that
that
user.
user
Or
or
in
in
other
other
words,
words
a
a
user
user
can
can
have
have
and
and
belong
belong
to
to
many
many
different
different
relationships.
relationships
It's
it's
your
your
typical
typical
social
social
graph
graph
data
data
model.
model
1st,
1st
we'll
we'll
go
go
to
to
the
the
Fauna
fauna
dashboard
dashboard
and
and
create
create
a
a
new
new
collection
collection
for
for
relationships.
relationships
Each
each
document
document
in
in
this
this
collection
collection
will
will
contain
contain
a
a
follower
follower
and
and
a
a
whose
whose
values
values
are
are
user
user
document
document
references.
references
You
you
can
can
think
think
of
of
this
this
document
document
as
as
an
an
edge
edge
in
in
a
a
graph
graph
that
that
connects
connects
2
2
user
user
accounts
accounts
together,
together
a
a
one
one
way
way
graph
graph
where
where
the
the
follower
follower
points
points
to
to
the
the
followee.
followee
Back
back
in
in
our
our
code,
code
we'll
we'll
set
set
up
up
a
a
new
new
relationship
relationship
endpoint
endpoint
That
that
creates
creates
the
the
relationship
relationship
document.
document
It
it
creates
creates
a
a
document
document
just
just
like
like
we
we
did
did
for
for
a
a
tweet.
tweet
The
the
only
only
difference
difference
is
is
that
that
we
we
point
point
to
to
the
the
relationship's
relationship's
collection.
collection
In
in
the
the
data
data
object,
object
the
the
follower
follower
and
and
the
the
followee
followee
are
are
just
just
user
user
references,
references
which
which
we
we
can
can
get
get
by
by
calling
calling
our
our
get
get
user
user
function
function
that
that
we
we
created
created
previously.
previously
For
for
now,
now
we'll
we'll
just
just
hard
hard
code
code
a
a
couple
couple
of
of
usernames
usernames
in
in
here
here
to
to
show
show
that
that
Bob
bob
follows
follows
Fireship.
fireship
We
we
can
can
now
now
go
go
ahead
ahead
and
and
make
make
a
a
post
post
request
request
to
to
the
the
relationship
relationship
endpoint
endpoint
and
and
we
we
should
should
get
get
a
a
new
new
document
document
back
back
that
that
has
has
a
a
follower
follower
and
and
a
a
with
with
a
a
user
user
reference
reference
on
on
it.
it
Now
now
that
that
we
we
can
can
establish
establish
a
a
relationship,
relationship
I
i
want
want
to
to
show
show
you
you
how
how
we
we
can
can
get
get
all
all
of
of
the
the
accounts
accounts
that
that
are
are
followed
followed
by
by
a
a
given
given
user.
user
And
and
not
not
just
just
the
the
accounts,
accounts
but
but
also
also
the
the
tweets
tweets
that
that
are
are
owned
owned
by
by
those
those
accounts
accounts
so
so
we
we
can
can
show
show
the
the
end
end
user
user
a
a
feed
feed
of
of
tweets
tweets
from
from
the
the
people
people
that
that
they
they
follow.
follow
The
the
first
first
step,
step
of
of
course,
course
will
will
be
be
to
to
create
create
a
a
new
new
index,
index
which
which
will
will
give
give
a
a
name
name
of
of
followers
followers
by
by
followee.
followee
It
it
will
will
take
take
the
the
followee's
followee's
user
user
reference
reference
then
then
return
return
all
all
the
the
accounts
accounts
that
that
that
that
user
user
is
is
following.
following
From
from
there,
there
we'll
we'll
go
go
back
back
to
to
our
our
code
code
and
and
create
create
a
a
new
new
get
get
endpoint
endpoint
for
for
feed.
feed
We'll
we'll
again
again
use
use
the
the
paginate
paginate
function
function
in
in
the
the
query,
query
but
but
this
this
time,
time
instead
instead
of
of
retrieving
retrieving
a
a
single
single
index,
index
we're
we're
going
going
to
to
join
join
2
2
indexes
indexes
together.
together
The
the
join
join
function
function
takes
takes
2
2
arguments.
arguments
The
the
first
first
one
one
is
is
the
the
initial
initial
thing
thing
that
that
you
you
want
want
to
to
query,
query
which
which
in
in
our
our
case
case
is
is
all
all
the
the
followed
followed
users,
users
which
which
we
we
can
can
get
get
by
by
pointing
pointing
to
to
our
our
recently
recently
created
created
index
index
and
and
then
then
a
a
specific
specific
username
username
like
like
Bob.
bob
That
that
will
will
give
give
us
us
all
all
of
of
the
the
user
user
references
references
that
that
are
are
followed
followed
by
by
Bob.
bob
We
we
can
can
then
then
join
join
all
all
the
the
tweets
tweets
from
from
those
those
users
users
by
by
using
using
the
the
index
index
tweets
tweets
by
by
user
user
as
as
the
the
second
second
argument.
argument
If
if
we
we
go
go
ahead
ahead
and
and
make
make
that
that
request,
request
You
you
can
can
see
see
that
that
we
we
now
now
get
get
the
the
text
text
from
from
multiple
multiple
tweets
tweets
back
back
from
from
that
that
index,
index
and
and
there's
there's
a
a
lot
lot
more
more
we
we
could
could
do
do
with
with
joins
joins
here.
here
Instead
instead
of
of
returning
returning
the
the
entire
entire
index,
index
we
we
could
could
use
use
a
a
Lambda
lambda
function
function
to
to
filter
filter
and
and
sort
sort
the
the
results
results
with
with
our
our
own
own
custom
custom
logic.
logic
But,
but
I
i
think
think
we'll
we'll
save
save
that
that
for
for
a
a
future
future
video.
video
I'm
i'm
gonna
gonna
go
go
ahead
ahead
and
and
wrap
wrap
things
things
up
up
there.
there
Fauna
fauna
is
is
a
a
truly
truly
awesome
awesome
database
database
and
and
the
the
more
more
I
i
use
use
it,
it
the
the
more
more
I
i
like
like
it.
it
If
if
I
i
were
were
starting
starting
a
a
new
new
project
project
today,
today
Fauna
fauna
would
would
definitely
definitely
be
be
at
at
the
the
top
top
of
of
my
my
list
list
for
for
the
the
tech
tech
stack.
stack
If
if
you
you
wanna
wanna
see
see
more
more
videos
videos
on
on
this
this
topic,
topic
let
let
me
me
know
know
in
in
the
the
comments.
comments
Consider
consider
supporting
supporting
my
my
work
work
with
with
a
a
GitHub
github
sponsorship,
sponsorship
or
or
by
by
becoming
becoming
a
a
pro
pro
member
member
at
at
Fireship
fireship
IO.
io
Thanks
thanks
for
for
watching,
watching
and
and
I
i
will
will
see
see
you
you
in
in
the
the
next
next
one.
one
success
The first database in the world is Fauna, which is serverless and scalable and is the first in the world to implement a Calvin model for partition database systems. Fauna is designed to handle complex data modeling use cases and is recommended for keeping SQL cheat sheets nearby. The speakers discuss Fauna's use of the index and the use of a code extension for code access control, as well as its use for creating a Twitter dashboard and a reference property. Fauna's use for creating a new collection for relationships and creating a dashboard are also discussed.
FaunaDB Basics - The Database of your Dreams
When you build an app, one of the main pain points that you'll face is your database. You often hear developers debate the merits of SQL versus NoSQL. On one hand, you have safety, security, and consistency. And, on the other, you have flexibility, scalability, and productivity. But, what if there's a database that could put an end to this debate once and for all? Fauna DB is the cloud database that I've always dreamed of. It's entirely serverless, so we don't have to provision anything and we only pay for what we actually use beyond the free tier. It's as easy to use as a document database. And, you can manage your data from its web interface or the command line. It's extremely fast and scales infinitely in the cloud and is the 1st database in the world to implement a Calvin model for partition database systems. Most importantly though, is its ability to handle complex data modeling use cases, like the ones you would find in a relational, no graph or time series database. Over the next few minutes, you'll learn everything you need to know to get up and running with FaunaDB. We'll use it to model the data relationships tips that you would find on Twitter. A user has many tweets, users can follow each other, and retrieve a feed of tweets from all the users that they follow. We'll write our code in Node. Js, and by the end of the video, you'll have an API that you can use to connect to your front end application. If you're new here, like and subscribe and check out the full write up on FireShip IO. To follow along today, the first thing you'll need is a free Fauna account. Once logged in, you'll see the Fauna dashboard. At this point, you won't have a database, so go ahead and click the button to create a new one. This is what's known as a top level database, and an awesome thing about Fauna is that it supports multi tenancy. It's beyond the scope of this video, but a cool feature you should know about. A database can have an unlimited number of child databases, allowing you to scope data and privileges to a specific organization or team. In most cases, though, you'll just need one single database for your entire per application. Now that we have a database, we'll create a collection. A collection is like an SQL table and works very similar to other document oriented databases like MongoDB or Firestore. A collection is kind of like a folder that contains many documents, then you can make queries against that collection to filter out a set of documents that you need for your front end UI. When you create a collection, you give it a name, which is usually plural. And in our case, it will store all of our user data. Now a unique thing about Fauna is that you'll also notice an option for history. It retains all of the changes that happen to a document over time. When you write to the database, Fauna never actually changes a stored document. Instead, it creates a copy of the original with the changes, then archives the original document to the history. That's extremely useful when working with time series data and also for time traveling through any changes to your data. You also have a TTL or time to live option, which can automatically delete ephemeral data that you no longer need. Now that we have our user's collection, let's go ahead and add a document to it. A document is represented as a plain JavaScript object. The data you save here does not need to follow a rigid structure. However, when you query multiple documents from a collection, it's based on the keys in this object. So if we want to match all of the users with a certain name or email address, we'll want to use the same key name in every document. Go ahead and click save, and now you should see that document in the collection. What you'll notice is that it's automatically assigned a unique ID to the document. Now if we expand the document, you can see in addition to our custom data, we also have a ref property that points to the user's collection along with that unique ID. The reference is very important because, eventually, we'll use it to join data together from multiple collections. In our case, for example, we could save a reference to this user on a tweet document so we know who a tweet belongs to, which is very similar to a foreign key in an SQL database. At this point, I'm going to add a few more users to the database, and now we need to think about how we want to access this data. There are multiple native APIs you can use to access data and Fauna. The first one that you might be familiar with is GraphQL. That's not the API we'll be using in this video. However, if you're familiar with GraphQL, you can actually upload a schema to Fauna and it will automatically create the collections and indexes required to retrieve your data based on that schema. It's really powerful stuff, but I think to really understand Fauna, you should learn its custom query language called FQL. You can execute FQL right here on the console, or you can install FaunaShell on your local system to execute it from the command line. And a little bit later, we'll learn how to use it in Node. Js. SQL is a functional language and is very intuitive and flexible, but there is a lot to learn. And I recommend keeping the SQL cheat sheet nearby. We'll look at about 10 of the most common functions, but just keep in mind that SQL can do a lot more than I present in this video. One of the first functions you'll wanna know is get, which retrieves a single document based on a reference. Get is just a function that takes a reference as an argument. We make a reference with the ref function, which takes a collection and a document ID as its arguments. If we then execute the query, we get the document data back as a result. And, as an added bonus, you'll notice if we hover over the information icon, it will tell us exactly how many bytes were transferred and a bunch of other useful information. Now, reading a single document is very easy when you have the ID, but in the real world, the document ID might not be readily available. And that brings us to our next big topic, Indexes. An index provides a way for you to define how to query documents from a collection. For example, we might want to fetch To user based on their email address or username instead of the actual document ID. A collection can have millions of documents, so an index provides a way to create a lookup table to quickly retrieve documents based on their actual internal data. 1st, we'll give our index a name, which in our case will be users by name. From there, we can specify 1 or more terms, which is a field on the document itself that can be searched. In our case, every user document has a name and we want to be able to fetch a user by the name. By default, the index will only return the document reference. But, another cool thing about Fauna is that you can tell the database which values from the document you want to return. In other words, you search a document by the username and then return the email address or whatever other data you want for the UI. That's an extremely useful little feature and we'll put it to use later in the video. Now, let's go back to the shell and we'll see how we can read a document with this index. Inside of git, we'll use the match function to search across an index. It takes the index as its first argument and then an array of search terms as the second argument. In this case, we just have the username which we can add as the second argument. And go ahead and execute the query, and you should get that same document back as the result. Now that we've explored the Fonta dashboard a little bit, we're going to switch gears into an actual Node JS application. Our goal is to build a simple REST API with Express that enables us to read and write to the database with our own custom code by making HTTP requests. You can follow along at this point by opening your IDE to an empty directory. You'll need to have Node JS installed on your system, and I'd also recommend installing the Fauna v s code extension. It allows you to see all of your collections and indexes right here in Versus Code, which is much easier than going back and forth to the dashboard. From this empty directory, we'll initialize a new npm project by running npm init with the y flag. That will give us a package JSON and then we can install FaunaDB and Express. From there, I'll create a source directory and add an index dotjs file to it, which is where we'll write all of our source code. Inside this file, we'll first require express, which will serve all of our API endpoints. And to interact with the database, we'll require FaunaDB and initialize the FaunaDB client. The client will connect your source code to the actual database in the cloud. And to do that, it requires a secret key, so let's head back to the Fauna dashboard. Board. Find the security tab, then create a new key to authenticate your server. By default, it gives you the choice between an admin and a server key. For our use case, we just need a server key. However, I would like to point out that you can implement fine grain access control right here from the Fauna dashboard. That makes it easy to follow the principle of least privilege where you only grant access to the bare minimum set of operations that are actually needed on the server. In any case, go ahead and copy the server key and then paste it into the Fonta DB client. The next thing we'll do in this file is start up our express server by calling app listen on port 5000. Now if you open the command line and run node pointed to your source directory, It will start up the server. And keep in mind that you'll need to restart it anytime the code changes. If that's too annoying for you, then check out nodemon to automatically reload anytime there's a change. Now, if you remember earlier, I mentioned that SQL is a functional language and we can import those functions and use them in JavaScript from the FaunaDB query namespace. As you can see, I've imported 10 different functions here and you don't need to know what they do at this point. The only important thing to know is that we use these functions to interact with the database. Now let's go ahead and set up our 1st API endpoint to read an individual tweet. We'll use express to set up a get endpoint that points to a tweet with its ID in the URL. Then for the callback, we'll set up an async function because any query you make to Fauna will return a promise. For this endpoint, we simply want to read a single document like we did earlier from the shell in the Fauna dashboard. Then we'll use the document itself as the response. We can make a request to Fauna for a document by awaiting a client query. Query takes an SQL expression as its argument. And remember, it's a functional language, so what you end up doing here is composing multiple JavaScript functions together. Conceptually, it's very similar to component composition in a UI framework like React. We'll start with the get function to read a single document, Then we use the ref function to make a reference to the document that we want. Ref takes 2 arguments. 1 is the collection that we want to read from, And the second is the document ID, which we'll get from the request parameters ID in the URL. And that's basically all there is to it. The promise will resolve with the actual document data, which we then send back as the response. One thing we're not doing here though is catching errors, but that would be a good idea. You can wrap the code in a try catch block, or you could simply chain the catch method to the other end of the promise. Now let's go ahead and test it out. At this point, we don't have any tweets in the database, So let's go back to Fauna and create a new collection for tweets, and then we'll add a document to it with the text of hello, world. Once created, go ahead and copy the document ID. Now at this point, we need to make a request to the URL. In my case, I'm using an HTTP client known as Insomnia. However, you could just use curl from the command line or a Versus Code extension to make these requests. In any case, what we need to do is make a get request to local host 5000/tweet followed by the tweet ID. When we send it, we should get the document back including the document data with the text of hello, world. Now that we know our API is working, we're going to look at some more complex examples of relational data. In this app, a user can have many tweets. But how do we connect a user document to a tweet document? Well, first, we need a way to create a tweet. And to handle that, we'll create a post endpoint that points to the tweet URL, and then we'll start with the same async function setup that we used in the previous endpoint. Creating a document is really easy. We just use the create function, point to the collection we want, and then pass it whatever custom data we want to save there. When we construct the data object, we can use regular JavaScript values or we can use SQL functions to get data from the database. In this case, we want the user field to be a reference to another user document in Fauna. There are many possible ways to do this, but one way is to use the select function, which will select a specific value from a document, which in this case is the reference. Now at this point, we might assume we only have the username, In which case, we can use our index, users by name, to get the corresponding user document reference. So the main takeaway here is that you can read 1 or more documents when performing some kind of other operation like a write to the database. And that allows you to model relational data in a way that's very similar to an SQL database with foreign keys. And it's also worth noting that Fauna is 100% ACID compliant, which means when you run this database transaction, it'll be globally consistent. Or, in other words, all future reads will reflect the value of the write, even when distributed across thousands of users around the world. If we go back to our HTTP client, We can make a post request to local host 5000/ tweet. Then we should get the newly created tweet back as the response. And And if you go to the Fauna dashboard, you should see it created in the user's collection there as well. Now that we have multiple tweets in the database, let's create an endpoint that can retrieve or query multiple tweets based on a username. Before we can make that query, we'll need an index. So let's go back to the Fauna dashboard and create a new index called tweets by user. The field we want to index here is the user reference to give us all the tweets owned by a user. And because we already have the user reference, we don't really need to have that returned on every single document. We can tell Fauna to only return the tweet text by setting it as a value. That way, we're only returning the actual data that we need for the UI. When we make this query, it's very similar to reading a single document, but instead of git, we use the paginate function. The difference here is that git returns the first match whereas paginate will return a set of documents that match that query. We then point to the index and then use select to grab the reference to the user. Now there is one thing that is bothering me at this point. We have some code duplication going on in our code base. Notice we're using the same exact select code for this query as we are in the previous endpoint. And getting a user is something we'll do often, so it's only going to get worse as we move forward. And that brings us to yet another awesome feature in Fauna called functions. Go ahead and copy the duplicated code and then head over to the Fauna dashboard and find the functions tab. A function allows you to Strack some SQL code so it can be used on any server or any platform. We'll give our function a name of get user and then apply it to the server role. Then in the function body, we have a query followed by a Lambda function. If you're not familiar with the Lambda function, just think of it like an anonymous arrow function in JavaScript. The value of x is something we pass into the function, then in the function body, we'll add our duplicated code. Instead of the hard coded username, we'll add a variable that points to x. And then we'll actually change the name of x to user just to make our code a little more readable. Now we can go back into our node app and reference this function. We'll need to import call and function. And And when you import function, you want to rename it something else using a colon because it collides with the built in function in JavaScript. Next, Let's find the duplicated lines of code that we want to replace. Now we can call the function by its name, get user, and then pass in whatever custom argument we want here, and it will be executed by Fonta remotely. So if you ever need to update this code, it gets updated throughout your entire code base atomically. The bottom line here is that functions provide an awesome way to keep your concise and maintainable. What we created is a one to many relationship where a user has many tweets, and a tweet belongs to a user. What we're going to look at next is the relationship between users, where a user can follow another user and or be followed by that user. Or in other words, a user can have and belong to many different relationships. It's your typical social graph data model. 1st, we'll go to the Fauna dashboard and create a new collection for relationships. Each document in this collection will contain a follower and a whose values are user document references. You can think of this document as an edge in a graph that connects 2 user accounts together, a one way graph where the follower points to the followee. Back in our code, we'll set up a new relationship endpoint That creates the relationship document. It creates a document just like we did for a tweet. The only difference is that we point to the relationship's collection. In the data object, the follower and the followee are just user references, which we can get by calling our get user function that we created previously. For now, we'll just hard code a couple of usernames in here to show that Bob follows Fireship. We can now go ahead and make a post request to the relationship endpoint and we should get a new document back that has a follower and a with a user reference on it. Now that we can establish a relationship, I want to show you how we can get all of the accounts that are followed by a given user. And not just the accounts, but also the tweets that are owned by those accounts so we can show the end user a feed of tweets from the people that they follow. The first step, of course, will be to create a new index, which will give a name of followers by followee. It will take the followee's user reference then return all the accounts that that user is following. From there, we'll go back to our code and create a new get endpoint for feed. We'll again use the paginate function in the query, but this time, instead of retrieving a single index, we're going to join 2 indexes together. The join function takes 2 arguments. The first one is the initial thing that you want to query, which in our case is all the followed users, which we can get by pointing to our recently created index and then a specific username like Bob. That will give us all of the user references that are followed by Bob. We can then join all the tweets from those users by using the index tweets by user as the second argument. If we go ahead and make that request, You can see that we now get the text from multiple tweets back from that index, and there's a lot more we could do with joins here. Instead of returning the entire index, we could use a Lambda function to filter and sort the results with our own custom logic. But, I think we'll save that for a future video. I'm gonna go ahead and wrap things up there. Fauna is a truly awesome database and the more I use it, the more I like it. If I were starting a new project today, Fauna would definitely be at the top of my list for the tech stack. If you wanna see more videos on this topic, let me know in the comments. Consider supporting my work with a GitHub sponsorship, or by becoming a pro member at Fireship IO. Thanks for watching, and I will see you in the next one.
The first database in the world is Fauna, which is serverless and scalable and is the first in the world to implement a Calvin model for partition database systems. Fauna is designed to handle complex data modeling use cases and is recommended for keeping SQL cheat sheets nearby. The speakers discuss Fauna's use of the index and the use of a code extension for code access control, as well as its use for creating a Twitter dashboard and a reference property. Fauna's use for creating a new collection for relationships and creating a dashboard are also discussed.