Skip to content

Instantly share code, notes, and snippets.

@bengitiger
Created January 15, 2018 02:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bengitiger/d99b28761a61918ccdf62fcb0429f3ee to your computer and use it in GitHub Desktop.
Save bengitiger/d99b28761a61918ccdf62fcb0429f3ee to your computer and use it in GitHub Desktop.
Sequelize + Express + Migrations + Seed Starter

Sequelize + Express Starter Guide

Based off of: http://docs.sequelizejs.com/en/1.7.0/articles/express/

Create your project directory

Create and initialize your a directory for your Express application.

$ mkdir sequelize-demo
$ cd sequelize-demo
$ npm init

Sequelize

Sequelize is an Object-Relation Mapping (ORM) library that allows you to treat your relational database schemas as objects in your JavaScript applications.

Install the sequelize command line tool

After you are inside the project directory, install sequelize-cli globally.

$ npm install sequelize-cli -g

This will allow us to use the sequelize is a command line tool that helps you create and manage your sequelize files.

In addition, you will need to also install sequelize module localy in order to utilize the command line tool.

$ npm install sequelize --save

Let's start by creating a our configuration file using:

$ sequelize init

This will generate a few files for you, your project folder should now look like this:

.
├── config
│   └── config.json
├── migrations
├── models
│   └── index.js
└── package.json

Configuring your database

For our example, you're going to be connecting to a Postgres database, we'll also need to install a couple more modules: pg and pg-hstore.

$ npm install pg pg-hstore --save

The generated config/config.json file begins with an environment level. This let's you configure different configurations for different environments, (e.g. – local development vs production).

Edit your development settings in config/config.json to point to your postgres database.

Example config/config.json

{
  "development": {
    "username": <your username>,
    "password": null,
    "database": "sequelize_demo",
    "host": "127.0.0.1",
    "dialect": "postgres"
  },
  ...
}

What are Migrations

Just like how we use Git to version control source code, we use migrations to manage the state of our database schemas.

I'm not really sure what that means...

Imagine you're working on project with another developer, and you're both tasked with creating a specific part of an event planning application. Let's say you are in charge of creating the Users and your friend is going to create the Events.

Let's say you and your friend divided the work in a way so that neither of you will have to to use each other's code to finish your tasks. While you're working on your part of the application, you only really need to touch the Users table when you are working with the database.

Before you begin

Make sure that the project you are in is a node project (it has a package.json) and you have already installed and initialized sequelize (npm install --save sequelize, sequelize init). Also make sure that your config.json file has the correct credentials to connect to your database.

Creating models and migrations

Using sequelize-cli you can easily create and manage your models and migrations. It has a useful command called model:create, which will generate 2 files for you: a model file and a corresponding migration file.

It has a couple handy options so that you can create your schemas from the command line:

Example Usage

sequelize model:create --name User --attributes first_name:string,last_name:string,bio:text
sequelize model:create --name Task --attributes title:string

Notice the --name and --attributes flags. these let us tell the program that we want to create a new model called User, that has 3 properties and their types:

  • first_name, type: string
  • last_name, type: string
  • bio, type: text

For a list of all the valid data types Sequelize has to offer, see: http://docs.sequelizejs.com/en/latest/api/datatypes/

This will generate 4 files for you: models/user.js

'use strict';
module.exports = function(sequelize, DataTypes) {
  var User = sequelize.define('User', {
    first_name: DataTypes.STRING,
    last_name: DataTypes.STRING,
    bio: DataTypes.STRING
  }, {
    classMethods: {
      associate: function(models) {
        // associations can be defined here
      }
    }
  });
  return User;
};

migrations/{timestamp}-create-user.js

'use strict';
module.exports = {
  up: function(queryInterface, Sequelize) {
    return queryInterface.createTable('Users', {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: Sequelize.INTEGER
      },
      first_name: {
        type: Sequelize.STRING
      },
      last_name: {
        type: Sequelize.STRING
      },
      bio: {
        type: Sequelize.TEXT
      },
      createdAt: {
        allowNull: false,
        type: Sequelize.DATE
      },
      updatedAt: {
        allowNull: false,
        type: Sequelize.DATE
      }
    });
  },
  down: function(queryInterface, Sequelize) {
    return queryInterface.dropTable('Users');
  }
};

models/Task.js

module.exports = function(sequelize, DataTypes) {
  var Task = sequelize.define("Task", {
    title: DataTypes.STRING
  }, {
    classMethods: {
      associate: function(models) {
        Task.belongsTo(models.User);
      }
    }
  });

  return Task;
};

and a similar Task migration file

Let's take a look at the migration file. If you look carefully at the name of the file, it will have the timestamp of when the migration file was created. This is on purpose so that sequelize can run the older migration files first, and then the newer ones that build on top of them. This is important later when changes need to be made to the database.

Also, it's guaranteed that your models and your migrations match. The migration files keep track of the state of the database schemas, and should always be created when changes to your models are made. Always commit coresponding migration files when changes to your models are made.

For a list of migration functions, see: http://sequelize.readthedocs.org/en/latest/docs/migrations/

Woops! Forgot a something...

Let's pretend you have jammed out 50 new commits while working with your newly created Users table, merged in your friends Events, and realize that you forgot to add in an email column to the table! Don't worry, this is not a problem.

sequelize migration:create --name add-email-to-user

This time you run the command, it only generates a migration file for you. When you open it, you notice it's pretty bare!

migrations/-add-email-to-user.js

'use strict';

module.exports = {
  up: function (queryInterface, Sequelize) {
    /*
      Add altering commands here.
      Return a promise to correctly handle asynchronicity.

      Example:
      return queryInterface.createTable('users', { id: Sequelize.INTEGER });
    */
  },

  down: function (queryInterface, Sequelize) {
    /*
      Add reverting commands here.
      Return a promise to correctly handle asynchronicity.

      Example:
      return queryInterface.dropTable('users');
    */
  }
};

But, because you're awesome and read the documentation, you know sequelize migrations has an addColumn function that will fix the problem for you!

After filling in the up and down functions, your migration file looks like this:

'use strict';

module.exports = {
  up: function (queryInterface, Sequelize) {
    queryInterface.addColumn( 'Users', 'email', Sequelize.STRING );
  },

  down: function (queryInterface, Sequelize) {
    queryInterface.removeColumn( 'Users', 'email' );
  }
};

It's important to always have both up and down methods in your migration script. Every time you run sequelize db:migrate it will call the up method. And if you ever want to revert backwards, you can call sequelize db:migrate:undo which will call the down method. They should always be opposite actions, this allows you to safely run migrations and know that the state of the database will be intact.

Not so fast! Update your model too!

Now that you fixed your migrations, you need to update your model to reflect the changes.

models/user.js

'use strict';
module.exports = function(sequelize, DataTypes) {
  var User = sequelize.define('User', {
    first_name: DataTypes.STRING,
    last_name: DataTypes.STRING,
    bio: DataTypes.TEXT,
    email: {
      type: DataTypes.STRING,
      validate: {
        isEmail: true
      }
    }
  }, {
    classMethods: {
      associate: function(models) {
        // associations can be defined here
      }
    }
  });
  return User;
};

Secret read unlocked! Validations: http://docs.sequelizejs.com/en/latest/docs/models-definition/#validations

Now if you run migrations, it will update your table to have emails as well!

sequelize_express=# SELECT * FROM "Users";
 id | first_name | last_name | bio | createdAt | updatedAt | email 
----+------------+-----------+-----+-----------+-----------+-------
(0 rows)

Seeding your database

When developing databases with it a team, it can be important that everyone is working with the same data. Or you might have information that you want to enter in your database initally, like admin accounts or something like that. You can do this with Seeders.

Using sequelize-cli you can easily create and manage your seed files. It has a useful command called seed:create, which will generate 2 files for you: a seed .

It has a couple handy options so that you can create your schemas from the command line:

Example Usage

sequelize seed:create --name my-seed-file

Running this command will result in a file in yoru seeders directory with code that looks like this:

'use strict';

module.exports = {
  up: function (queryInterface, Sequelize) {
    /*
      Add altering commands here.
      Return a promise to correctly handle asynchronicity.

      Example:
      return queryInterface.bulkInsert('Person', [{
        name: 'John Doe',
        isBetaMember: false
      }], {});
    */
  },

  down: function (queryInterface, Sequelize) {
    /*
      Add reverting commands here.
      Return a promise to correctly handle asynchronicity.

      Example:
      return queryInterface.bulkDelete('Person', null, {});
    */
  }
};

As with your model. it's important to always have both up and down methods in your seed script.

After filling in the up and down functions, your migration file looks like this:

'use strict';

module.exports = {
  up : function (queryInterface, Sequelize) {
    return queryInterface.bulkInsert('Users', [{
      first_name : 'John',
      last_name : 'Doe',
      bio : 'I am a new user to this application',
      createdAt : new Date(),
      updatedAt : new Date(),
      email : 'johnDoe@test.com'
    }], {});
  },

  down : function (queryInterface, Sequelize) {
    queryInterface.bulkDelete('Users', [{
      first_name :'John'
    }])
  }
};

You can seed your database with this data by running this sequelize-cli command:

$ sequelize db:seed:all

After this command, and check your database, you should have something that looks like this:

sequelize_express=# SELECT * FROM "Users";
  id | first_name | last_name |                 bio                 |         createdAt          |         updatedAt          |      email
----+------------+-----------+-------------------------------------+----------------------------+----------------------------+------------------
  1 | John       | Doe       | I am a new user to this application | 2016-04-25 14:35:06.269-10 | 2016-04-25 14:35:06.269-10 | johnDoe@test.com
(1 rows)

Create your Express application

$ npm install express --save

Create your express application how you normally would, for this example the server listening on port 3000.

var express = require('express');
var app = express();

var db = require('./models');

app.listen(3000, function() {
  db.sequelize.sync();
});

Start the server:

$ npm start

After the server starts, db.sequelize.sync is invoked, this will automatically synchronize your application with the database. If all goes well your server should have a bunch of SQL queries that will create all of your tables for you!

Making models

After successfully creating your express application, create a route to allow users to create new Users in the database.

Get user input

For this example, install the body-parser module, set it up to parse JSON payloads.

$ npm install body-parser --save

Models

After you have set up the body-parser, add another line of code that requires your User model from your db object.

var User = db.User;

This will let you access the User model so that you can create and read from your database.

Creating users

app.post('/users', function (req, res) {
  User.create({ 
    first_name: req.body.first_name,
    last_name: req.body.last_name,
    bio: req.body.bio,
    email: req.body.email,
  })
    .then(function (user) {
      res.json(user);
    });
});

Getting users

app.get('/users', function(req, res) {
  User.findAll()
    .then(function (users) {
      res.json(users);
    });
});

Create some users!

Using Postman, send POST requests and GET requests to create and fetch users added to your database.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment