An important step in building an application is creating an interface to your data. The use cases of your data may vary, but the process through which the data is stored and accessed is largely the same. Models sit between your application's logic and the data store itself. A good model should create a standard interface to the data store, and remove the burden of configuration and implementation from the rest of your application.

In this two-part series, we'll create a generic data model for a JavaScript NoSQL solution and discuss common data model patterns.

Data Models for NoSQL

If you're coming from a relational database background, NoSQL models require more attention up front. When building models for a relational database, it's easy for developers to let the database manage type and relationship constraints. In a NoSQL model, there are no database constraints; it's the application that enforces the schema.

Developers should take the time to understand their data and how it will be accessed during the life cycle of a request. While it's tempting to throw JSON documents into a collection, you'll end up creating inconsistent documents that will cost you twice the time to fix later.

Initialization

Using Mongoose and MongoDB, we'll create a simple, reusable, and inheritable model object that will set the foundation of our custom application models. Our finished product can be found here. We want to be able to create our own classes that represent each collection in our application. We'll add more features and functionality as we progress through the series.

Tools Used

MongoDB is a powerful open-sourced NoSQL document database solution. It focuses on speed and reliability and has advanced capabilities such as full-text search.

Mongoose is a Node.js library that provides a schema-based database modeling solution for MongoDB.

CenturyLink Cloud Compute servers are high-performance cloud servers. These enterprise-grade virtual machines are easy to deploy and manage from the CenturyLink Cloud Console and via our powerful API.

Deploy a New Virtual Server with MongoDB

If you don't have a CenturyLink Cloud account yet, head over to our website and sign up for a free trial. You'll need it to access CenturyLink Cloud products.

Our first step is to deploy a new CenturyLink Cloud virtual server. Follow the steps below.

  1. Log into the CenturyLink Cloud control portal at https://control.ctl.io/
  2. On the left side menu, click Infrastructure and then Servers.

    node

  3. On the left-hand side of the server panel, click on the region for the server we will provision.

  4. Click create and then server.
  5. Complete the setup form for your new server. Be sure to fill out the fields for server name and admin/root password.
  6. For operating system, select "CentOS 7 | 64-bit".
  7. Click create server.
  8. Your server provisioning request will enter the queue. You can watch the progress of your request on the screen. Your server is provisioned when the status of all tasks in the queue is complete.

    node

  9. After your new server is provisioned, in the CenturyLink control portal, click Infrastructure on the left side menu, and then click Servers.

  10. Navigate to your new server and click on its name.
  11. Click the more menu, and then click add public ip.
  12. Check the box for SSH/SFTP (22).
  13. Click custom port... and then single port.
  14. Type "27017" in the blank box to open up the MongoDB server port.

    node

  15. Click add public ip address.

Installing and Configuring MongoDB

  1. Navigate to your server in the CenturyLink Cloud control panel as in the previous section. Your server's public IP address will be noted on the screen.
  2. From a shell on your local machine, connect to your new server with the following command. Replace "YOUR.VPS.IP" with your server's public IP address.

    ssh [email protected]
    
  3. Install the MongoDB server software by running the following commands.

    $ yum install -y mongodb mongodb-server
    
  4. With your favorite text editor, open /etc/mongod.conf. Look for the line that begins "bind_ip" and comment it out. The top of your file should now look like this:

    ##
    ### Basic Defaults
    ##
    
    # Comma separated list of ip addresses to listen on (all local ips by default)
    #bind_ip = 127.0.0.1
    
  5. Start the MongoDB service by running the following command.

    $ service mongod start
    

Building the Schema Model

You can follow along with building the schema model by downloading the finished sample application from this GitHub project.

First, we need to make sure that all of the required packages are installed. Run these commands in your shell from the project directory.

npm install mongoose --save
npm install bluebird --save
npm install assert --save

Note: If you are following along from the GitHub project, you only need to run one command: npm install

Next we need to create a database connection. In your project directory, create a file called config.js with the following contents. Replace "YOUR.MONGODB.HOST" with the IP address of your MongoDB server.

// config.js
module.exports = {
  "mongodbHost" : "YOUR.MONGODB.HOST",
  "mongodbDb" : "movies"
}

Now we can initialize the database connection and load the libraries needed to build models. The following code goes into your main application file, usually index.js.

const assert = require('assert');
var config = require('./config.js');
var mongoose = require('mongoose');

mongoose.connect('mongodb://' + config.mongodbHost + '/' + config.mongodbDb);

var db = mongoose.connection;

The Mongoose library can also be configured to use any JavaScript Promise library that follows the Promises/A+ standard. We will load the Bluebird library.

var Promise = require('bluebird');
mongoose.Promise = Promise;

Now, we want to connect to the MongoDB database and initialize a model for our movie application. That will look like the following example. You will notice that we have not yet initialized a schema object.

db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function() {
  console.log('Connected to database!');

  schema.Movie.findOne({title: 'Tremors'})
    .then(function (movie) {
      console.log("Movie title:", movie.title);
    })
    .finally(function () {
      db.close();
    });
});

Creating the Model Object

Now we can create connections, so it's time to generate models. We need to prepare a model for our movie object. Create a file called lib/schema.js and start it out like the following.

// schema.js
const assert = require('assert');
var mongoose = require('mongoose');
var Schema = mongoose.Schema;

// Create schemas to store movie and actor documents.
var movieSchema = new Schema ({
  title: String,
  year: Number,
  actors: [Schema.Types.ObjectId]
})

// Takes a mongoose DB as argument.
module.exports = function (db) {
  assert.notEqual(null, db);

  // Add your schema models to Mongoose.
  this.Movie = db.model('Movie', movieSchema);

  return this;
};

This module takes an argument when it's loaded, which allows your application to have multiple MongoDB database connections. In index.js, you can use it like this.

var schema = require('./lib/schema.js')(db);

Notice how simple it is to make use of Mongoose model methods to create collection-specific functionality! In the movieSchema structure, you see an example of a type constraint to make sure that the year attribute is an integer. This frees your models up from excessive boilerplate and allows you to focus on how data flows through your application.

In the next section we'll discuss data modeling in JSON and add features to our model that demonstrate relationships between document collections and records.