Building an e-Commerce website with Node – Part 08 – Creating user schema with mongoose and bcrypt

In this post I am going to show you how to code your first database design using a library named Mongoose and a library named bcrypt.

Mongoose is an object relational mapper, a virtual object database, or as they call it on the official website, “Elegant MongoDB object modeling for Node.js”. Mongoose does all the dirty work to connect Node.js to the MongoDB database.

Bcrypt is a library to hash a password before saving it to the database.

To get started we need to create a new folder within our project folder. I called it “models”. This folder is going to store all the database schemata (the blueprint of your database).

Under models folder create a file and name it user.js. In this file we are going to require the mongoose library and the bcrypt library (just as we required the libraries in server.js file). We also declare a new variable named Schema to work easier with mongoose.Schema.


var mongoose = require('mongoose');
var bcrypt = require('bcrypt-node.js');
var Schema = mongoose.Schema;

Below our requests, we are going to create three sections where our code will be placed:

  • User schema attributes
  • Hash passwords before saving to the database
  • Compare password (database vs. what the user types in)

The first section contains all the attributes related to the user.


// User schema attributes
var UserSchema = new Schema({
  email: { type: String, unique: true, lowercase: true},
  password: String,

  profile: {
    name: { type: String, default: ''},
    picture: { type: String, default: ''}
  },

  address: String,
  history: [{
    date: Date,
    paid: { type: Number, default: 0},
  }]
});

First we create a new variable named UserSchema which is a new instance of Schema. This variable will store all the data about a user.

The first data is the email which is a string, has to be unique, and has to be lowercased.
The second data is the password which has to be a string.
The third data is the profile (of the user). The profile contains the name which has to be string and by default, if the user doesn’t type anything, it will show just an empty field. Basically, the user won’t have a name. The picture is just as the name, a string and an empty field by default.
The fourth data is the address which has to be a string.
The fifth data is the history (when did the user buy and how much did he pay).

The second section of the file hashes the password before it is saved to the database.


// Hash passwords before saving to the database
UserSchema.pre('save', function(next) {
  var user = this;
  if (!user.isModified('password')) return next();
  bcrypt.genSalt(10,function(err, salt) {
    if (err) return next(err);
    bcrypt.hash(user.password, salt, null, function(err, hash) {
      if (err) return next(err);
      user.password = hash;
      next();
    });
  });
});

pre is one of the mongoose methods which pre-save passwords before saving to the database.
this is just an object that is referring to the UserSchema.
gen.Salt() is one of the bcrypt methods which will create the salt (salt is just random data). In our case it will generate 10 random data (something like a1d894e77k)
if (err) return next(err); it checks for errors and validates.
bcrypt.hash() is a bcrypt method. We pass in the password typed by the user and the generated salt for that password. The third parameter null means progress. The fouth parameter is an anonymous function which takes in two parameters (err and hash). It checks for errors and if there is an error it returns a callback with the error, otherwise it sets the user.password to hash.
next() is a call back with no parameter which basically means “go ahead”.

The third section just compares the password typed by the user with the password stored in the database.


// Compare password (database vs. what the user types in)
UserSchema.methods.comparePassword = function(password) {
  return bcrypt.compareSync(password, this.password)
}

First we create a custom method UserSchema.methods.comparePassword. When you create a custom method you have to use the keyword “methods”. This method we create is a function which takes in an argument, password. The function returns a built in method of bcrypt which is called compareSync.

We will test our UserSchema after we configure the MongoDB database and create a route for the UserSchema.

Leave a Reply