Chapter 4: Databases, Part 1

Databases, Part 1

One of the most difficult parts of teaching people how to build things with Meteor is figuring out when to introduce certain ideas. There’s a number of topics we have to cover, but the order in which we talk about these topics can drastically affect whether or not readers retain any of the details.

One mistake teachers make when teaching web development, for instance, is starting a book by showing readers how to build a user interface. This approach is fun, because students can see the visual results of their code, which allows them to feel like they’re making quick progress, but this approach also introduces a couple of problems:

  1. It’s difficult to grasp what’s truly happening on the front-end (the interface) if you’re not familiar with what’s happening on the back-end (the database, etc).
  2. If we talk about the front-end first, we’ll have to back-track in the next chapter anyway, so any feeling of quick progress will be short-lived.

Because of this, we’re going to start by talking about how to create and manage a database within our project. This isn’t the most exciting topic in the world, but if we spend a few minutes covering the basics, we’ll have a much stronger foundation for the rest of the chapters.

Then we can focus on the fun stuff.

Mongo vs. SQL

If you’ve ever built something on the web before, you’ve probably come across some kind of database. If you’ve installed a copy of WordPress, for instance, then you would have come into contact with an SQL database.

By default, every Meteor project comes with a database. When you create a project, the database is automatically created, and when the local server is running, so is that database. There’s no setup or configuration required. Everything “just works” right out of the box.

But this database is not an SQL database.

Instead, it’s what known as a “Mongo” database.

If you’ve never come across Mongo before, that’s fine. Mongo databases are different from SQL databases, but those differences are relatively small as far as beginners are concerned.

For the moment, it’s mostly important to know that Mongo uses different words to describe familiar concepts. We won’t, for instance, use words like “tables” and “rows”, but the concepts can be thought of in the same way.

Here’s a breakdown of how the terminology differs:

It can be tricky to think of familiar concepts with new words, but I’ll offer plenty of reminders as we make our way through this book. And if you’re starting to question whether or not you have enough database experience to make the most of the coming chapters, then rest assured that we’re only going to touch on the fundamentals. You’ll want to eventually learn about Mongo independently, but for the time being we’ll be moving slow enough that you shouldn’t have any trouble following along.

Create a Collection

The main feature of the Leaderboard application is the list of players.

Without displaying a list of players inside the interface, we can’t build anything else of value. As such, it’s the best place to start working on the application – from the “middle” and working out toward the finer details.

But this begs the question:

Where do we store the data that will be associated with each player? Where do we store their names, for instance? Or their scores?

The broad answer would be in a database, but the more useful answer would be in a collection, and as we saw in the previous section, a Mongo collection is equivalent to an SQL table.

To illustrate the purpose of a collection, imagine we’re creating our own version of WordPress. If that were the case, we’d create a collection for the posts, and a collection for the comments, and a collection for the pages. We’d create a collection for each type of data.

Since we’re creating this Leaderboard application though, we’ll create a collection for the players.

To do this, open the JavaScript file and write the following statement:

new Mongo.Collection('players');

Here, we’re creating a Mongo collection named “players”. You can call the collection whatever you want, but the name must be unique. If the name is not unique, Meteor will return an error.

But while this statement creates a collection, we haven’t defined a way to reference the collection, and therefore we have no way to manipulate it.

To fix this, place the statement inside a variable:

PlayersList = new Mongo.Collection('players');

But notice that we didn’t use the var keyword. This is because we want the variable to be a global variable. This allows us to reference the collection throughout all of the project’s files.

To confirm that the collection exists: save the file, switch to the browser, and enter the name of the collection’s variable into the Console:

PlayersList

Then tap the “Return” key.

You should see some mildly cryptic information returned as a result.

If an error is returned, it’s probably because you mistyped the name of the variable in the Console, or made a syntactical mistake in the code.

Inserting Data

To insert the data into a collection, we have three main options. We can insert data through the JavaScript Console, from inside a JavaScript file, or by using a form inside the interface.

We’ll see how all of these options work in this book, but using the Console is the easiest place to start, so that’s what we’ll focus on for the time being.

Inside the console, write the following:

PlayersList.insert();

This is the syntax we use for manipulating a collection. We start with the variable assigned to the collection – in this case, the “PlayersList” variable – and then attach a function to it. Here, we’re using the insert function, but there’s a range of other functions available, including find, update, and remove, and we’ll talk about these later in the book.

But if we tapped the “Return” key at this point, nothing would happen, and that’s because we need to pass data into the function for it to actually manipulate the contents of the collection.

The data we pass into the function needs to be in the JSON format, but if you’re not familiar with the JSON format, here’s what it looks like:

{
    name: "David",
    score: 0
}

Here, there’s a few things worth nothing:

  1. The data is wrapped in a pair of curly braces. These braces distinguish the JSON data from the rest of the code.

  2. We’ve defined a pair of keys. These keys are known as name and score, and in Mongo terminology, these are the fields for this collection. So because every player in the collection will have a name and a score associated with them, we’ve defined these keys to hold these values.

  3. We’ve defined the values associated with the keys. In this case, the value of the name field is “David” and the value of the score field is “0” (without quotes).

  4. The keys and values are separated with commas. This is because the JSON format ignores white-space, so commas are used to structure the data.

To insert this data into the “PlayersList” collection, pass it into an insert function, and place that function inside the Console:

PlayersList.insert({ name: "David", score: 0 });

Then tap the “Return” key.

When this statement is executed, a document will be created inside the “PlayersList” collection. Documents in Mongo are equivalent to rows in SQL, and at this stage, we want to create one document for every player we want in our collection. If we want six players on the leaderboard, we can use the insert function six times, thereby creating six documents in the collection.

Before we continue, insert a few more players in the collection.

To do this, use the insert function a few more times, but define a unique value for the name field so we can distinguish between the various players in the list:

PlayersList.insert({ name: "Bob", score: 0 });

The players in my list are:

  • David
  • Bob
  • Mary
  • Bill
  • Warren
  • Tim

Also notice that, after creating each document, a random jumble of numbers and letters appears inside the Console. This jumble is a unique ID that is created by Mongo and associated with that particular document. This ID is known as the primary key and it’ll be important later on.

Finding Data

Now that we have some data in the collection, we can retrieve that data. We’ll retrieve and display that data through the interface in the next section, but for the moment, we’ll keep things simple by retrieving it through the Console.

Inside the Console, write the following statement:

PlayersList.find();

Here, we’re using this find function, which is used to retrieve data from a specified collection. Unlike the insert function though, we don’t have to pass anything between the parentheses. If we leave the function empty, it will retrieve all of the data from the collection.

If you tap the “Return” key, then, the following data should appear inside the Console:

Obviously though, this is not very readable output. Meteor can make sense of it, but we can’t.

To retrieve data in a human-readable format, use the same find function for a second time, but attach a fetch function to the end of it:

PlayersList.find().fetch();

This will retrieve the data from the collection as an array of objects, which is easier for us to both read and navigate.

You’ll also notice that each document – each player – in the collection is represented by these individual objects, and if we click on the downward-facing arrows, we can see the data associated with each of them.

Each document has:

  • An _id field, which contains the unique ID of the player (the primary key) that we discussed in the previous section.
  • A name field, which contains the name of the player.
  • A score field, which contains the score of the player.

But what if we wanted to only retrieve a selection of data from the collection?

To do this, we can pass a JSON formatted query between the parentheses of the find function:

PlayersList.find({ name: "David" }).fetch();

Here, we’re passing a field name and a value into the find function, and as a result, we’re able to retrieve only the documents in the collection where the player’s name field is equal to “David”. In this case, this query only retrieves one document, but if the collection contained multiple players named “David”, they would all be returned based on this query.

What’s also useful is the ability to count the number of documents returned by the find function by attaching a count function to the end of it:

PlayersList.find().count();

Since this statement will find and then count all of the documents in the collection, if there’s six documents (players) in the collection, the number 6 will be returned.

Summary

In this chapter, we’ve learned that:

  • When we create a Meteor project, a Mongo database is created for us.
  • When the local server is running, so is the project’s database.
  • Mongo databases are different from SQL databases, but we don’t need to think about these differences at this stage in the learning process.
  • Within a Mongo database, we create a collection for each type of data. These collections contain documents, while documents contain fields and values.
  • By using the insert function, we can insert data into a collection. This data must be structured in the JSON format.
  • By using the find function, we can retrieve data from a collection. This data can then be browsed via the JavaScript Console.

To gain a deeper understanding of Meteor:

  • Notice that we haven’t predefined a structure for the database. Instead, the structure of the data is defined each time we use the insert function.
  • In a separate project, create a collection that stores a different type of data, such as blog posts. What sort of fields would that collection have?

To browse the project’s code in its current state, click here.