Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Meteor: Full-Stack Web Application Development

You're reading from   Meteor: Full-Stack Web Application Development Rapidly build web apps with Meteor

Arrow left icon
Product type Course
Published in Nov 2016
Publisher Packt
ISBN-13 9781787287754
Length 685 pages
Edition 1st Edition
Languages
Tools
Arrow right icon
Authors (2):
Arrow left icon
Fabian Vogelsteller Fabian Vogelsteller
Author Profile Icon Fabian Vogelsteller
Fabian Vogelsteller
Marcelo Reyna Marcelo Reyna
Author Profile Icon Marcelo Reyna
Marcelo Reyna
Arrow right icon
View More author details
Toc

Chapter 3. Storing Data and Handling Collections

In the previous chapter, we learned how to build templates and display data in them. We built the basic layout of our app and listed some post examples on the front page.

In this chapter, we will add post examples persistently to our database on the server. We will learn how we can access this data later on the client and how Meteor syncs data between clients and the server.

In this chapter, we'll cover the following topics:

Meteor and databases

Meteor currently uses MongoDB by default to store data on the server, although there are drivers planned for use with relational databases too.

Note

If you are adventurous, you can try one of the community-built SQL drivers, such as the numtel:mysql package from https://atmospherejs.com/numtel/mysql.

MongoDB is a NoSQL database. This means it is based on a flat document structure instead of a relational table structure. Its document approach makes it ideal for JavaScript as documents are written in BJSON, which is very similar to the JSON format.

Meteor has a database everywhere approach, which means that we have the same API to query the database on the client as well as on the server. Yet, when we query the database on the client, we are only able to access the data that we published to a client.

MongoDB uses a data structure called collection, which is the equivalent of a table in a SQL database. Collections contain documents, where each document has its own unique ID. These documents are JSON-like structures and can contain properties with values, even with multiple dimensions, as follows:

{
  "_id": "W7sBzpBbov48rR7jW",
  "myName": "My Document Name",
  "someProperty": 123456,
  "aNestedProperty": {
    "anotherOne": "With another string"
  }
}

These collections are used to store data in the server's MongoDB as well as the client-side minimongo collection, which is an in-memory database mimicking the behavior of the real MongoDB.

Note

We'll discuss more about minimongo at the end of this chapter.

The MongoDB API allows us to use a simple JSON-based query language to get documents from a collection. We can pass additional options to only ask for specific fields or sort the returned documents. These are very powerful features, especially on the client side, to display data in various ways.

Setting up a collection

To see all this in action, let's get right on it by creating our first collection.

We create a file called collections.js inside our my-meteor-blog folder. We need to create it in the root folder so that it will be available on both the client and the server. Now let's add the following line of code to the collections.js file:

Posts = new Mongo.Collection('posts');

This will make the Posts variable globally available, as we haven't used the var keyword, which would restrict it to the scope of this file.

Mongo.Collection is the API used to query the database and it comes with the following basic methods:

  • insert: This method is used to insert documents into the database
  • update: This method is used to update documents or parts of them
  • upsert: This method is used to insert or update documents or parts of them
  • remove: This method is used to delete documents from the database
  • find: This method is used to query the database for documents
  • findOne: This method is used to return only the first matched document

Adding post examples

To query the database for posts, we need to add some post examples. This has to be done on the server, as we want to add them persistently. To add an example post, perform the following steps:

  1. We create a file called main.js inside our my-meteor-blog/server folder. Inside this file, we will use the Meteor.startup() function to execute the code on the start of the server.
  2. We then add the post example, but only when the collection is empty. So to prevent this, we add them every time we restart the server, as follows:
    Meteor.startup(function(){
    
      console.log('Server started');
    
      // #Storing Data -> Adding post examples
      if(Posts.find().count() === 0) {
    
        console.log('Adding dummy posts');
        var dummyPosts = [
          {
            title: 'My First entry',
            slug: 'my-first-entry',
            description: 'Lorem ipsum dolor sit amet.',
            text: 'Lorem ipsum dolor sit amet...',
            timeCreated: moment().subtract(7,'days').unix(),
            author: 'John Doe'
          },
          {
            title: 'My Second entry',
            slug: 'my-second-entry',
            description: 'Borem ipsum dolor sit.',
            text: 'Lorem ipsum dolor sit amet...',
            timeCreated: moment().subtract(5,'days').unix(),
            author: 'John Doe'
          },
          {
            title: 'My Third entry',
            slug: 'my-third-entry',
            description: 'Dorem ipsum dolor sit amet.',
            text: 'Lorem ipsum dolor sit amet...',
            timeCreated: moment().subtract(3,'days').unix(),
            author: 'John Doe'
          },
          {
            title: 'My Fourth entry',
            slug: 'my-fourth-entry',
            description: 'Sorem ipsum dolor sit amet.',
            text: 'Lorem ipsum dolor sit amet...',
            timeCreated: moment().subtract(2,'days').unix(),
            author: 'John Doe'
          },
          {
            title: 'My Fifth entry',
            slug: 'my-fifth-entry',
            description: 'Korem ipsum dolor sit amet.',
            text: 'Lorem ipsum dolor sit amet...',
            timeCreated: moment().subtract(1,'days').unix(),
            author: 'John Doe'
          }
        ];
        // we add the dummyPosts to our database
        _.each(dummyPosts, function(post){
          Posts.insert(post);
        });
      }
    });

Now, when check out the terminal, we should see something similar to the following screenshot:

Adding post examples

Note

We can also add dummy data using the Mongo console instead of writing it in our code.

To use the Mongo console, we start the Meteor server using $ meteor, and then in a second terminal we run $ meteor mongo, which brings us to a Mongo shell.

Here, we can simply add documents using MongoDB's syntax:

db.posts.insert({title: 'My First entry',
  slug: 'my-first-entry',
  description: 'Lorem ipsum dolor sit amet.',
  text: 'Lorem ipsum dolor sit amet...',
  timeCreated: 1405065868,
  author: 'John Doe'
}
)

Querying a collection

The server did restart when we saved our changes. At this point, Meteor added five post examples to our database.

Note

If the server didn't restart, it means that we made a mistake in the syntax somewhere in our code. When we manually reload our browser or check out the terminal, we will see the error that Meteor gives us and we can fix it.

In case we messed up something in the database, we can always reset it using the $ meteor reset command in the terminal.

We can see these posts by simply opening up the console in our browser and typing the following command:

Posts.find().fetch();

This will return an array with five items, each of them being one of our example posts.

To list these newly inserted posts in our front page, we need to replace the content of our postsList helper in the home.js file with the following lines of code:

Template.home.helpers({
  postsList: function(){
    return Posts.find({}, {sort: {timeCreated: -1}});
  }
});

As we can see, we returned the collections cursor directly in the helper. This return value then gets passed to the {{#each}} block helper in our home template, which will then iterate over each post while rendering the postInList template.

Note

Note that Posts.find() returns a cursor, which is more efficient when used in an {{#each}} block helper, whereas Posts.find().fetch() will return an array with the document objects. Using fetch(), we can manipulate the documents before returning them.

We pass an options object as the second parameter to the find() function. The option we are passing will sort the result based on timeCreated and -1. The -1 value means it will be sorted in descending order (1 means ascending order).

Now, when we check out our browser, we will see that all of our five posts are listed, as shown in the following screenshot:

Querying a collection

Updating a collection

Now that we know how to insert and fetch data, let's take a look at how to update data in our database.

As we've already seen before, we can use the console of our browser to play with the database. For our next examples, we will use only the console to see how Meteor reactively changes the templates when we change data.

To be able to edit a post in our database, we first need to know the _id field of its entry. To find this out, we need to type the following command:

Posts.find().fetch();

This will return us all the documents in the Posts collection, as we are not passing any specific query object.

In the returned array, we need to take a look at the last item, with the My Fifth entry title, and copy the _id field to the clipboard using Cmd + C (or Ctrl + C if we're on Windows or Linux).

Note

We can also simply use Posts.findOne(), which will give us the first document it finds.

Now that we have _id, we can simply update the title of our fifth post by typing the following command:

Posts.update('theCopied_Id', {$set: {title: 'Wow the title changed!'}});

As soon as we execute this command, we will notice that the title of the fifth post has changed to our new title, and if we now reload the page we will see that the title stays the same. This means the change was persistently made to the database.

To see Meteor's reactivity across clients, open up another browser window and navigate to http://localhost:3000. When we now change our title again by executing the following command, we will see that all the clients get updated in real time:

Posts.update('theCopied_Id', {$set: {title: 'Changed the title again'}});

Database everywhere

In Meteor, we can use the browser console to update data, which means that we can update the database from the client. This works because Meteor automatically syncs these changes to the server and updates the database accordingly.

This happens because we have the autopublish and insecure core packages added to our project by default. The autopublish package automatically publishes all documents to every client, whereas the insecure package allows every client to update database records by its _id field. Obviously, this works well for prototyping but is infeasible for production, as every client can manipulate our database.

If we remove the insecure package, we will need to add "allow and deny" rules to determine what a client is allowed to update and what they are not; otherwise, all updates will get denied. We will take a look at setting these rules in a later chapter, but for now this package serves us well, as we can immediately manipulate the database.

In the next chapter, we will see how to manually publish only certain documents to a client. We will start that by removing the autopublish package.

Differences between client and server collections

Meteor has a database everywhere approach. This means it provides the same API on the client as well as on the server. The data flow is controlled using a publication subscription model.

On the server sits the real MongoDB database, which stores data persistently. On the client, Meteor has a package called minimongo, which is a pure in-memory database mimicking most of MongoDB's query and update functions.

Every time a client connects to its Meteor server, Meteor downloads the documents that the client has subscribed to and stores them in its local minimongo database. From here, they can be displayed in a template or processed by functions.

When the client updates a document, Meteor syncs it back to the server, where it is passed through any allow/deny functions before being persistently stored in the database. This also works the other way; when a document in the server-side database changes, it will automatically sync to every client that is subscribed to it, keeping every connected client up to date.

Summary

In this chapter, we learned how to store data persistently in Meteor's MongoDB database. We also saw how we can query collections and update documents. We understood what the "database everywhere" approach means and how Meteor keeps every client up to date.

To dig deeper into MongoDB and to query and update collections, take a look at the following resources:

You can find this chapter's code examples either at https://www.packtpub.com/books/content/support/17713 or on GitHub at https://github.com/frozeman/book-building-single-page-web-apps-with-meteor/tree/chapter3.

In the next chapter, we will see how to control the data flow using publications and subscriptions so that we send only the necessary documents to the clients.

You have been reading a chapter from
Meteor: Full-Stack Web Application Development
Published in: Nov 2016
Publisher: Packt
ISBN-13: 9781787287754
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime
Banner background image