Welcome folks I am back with another blog post. In this blog post We will be building a Complete Node Express and MongoDB CRUD Project with Validation. All the source code will be available to download in a zip file. The video is given below explaining each instruction which is written in the blog post. Let’s get started with the post.

Prerequisites

There are some things you should know before making this CRUD Application. The list of technologies you should know are as follows:

Node : You should have a basic knowledge of Node. Express : You have should knowledge in working with the express library MongoDB : You should have some background on MongoDB.

Installing Dependencies

Now we will install the required node packages for making this application. The list of packages which will be required for making this application are as follows:

body-parser : This package will be used to handle the data which will be coming from the request and it will be converting the request data to json format. Mongoose : This will be the package required to connect our MongoDB Database and the node application that we are building. email-validator: This package from the name itself will be used to validate email addresses. nodemon: This will be a dev dependency which will be required to restart the server automatically when we make any kind of changes to the application. express-handlebars: This will be the node package which will be used to build our interface of the application. It is similar to jade package. But in this application we will be using the handlebars library which is related to express. express : Lastly we will install express to make the backend server of the application.

Now create a new folder call it anything and inside it folder open the cmd and then check if you node installed or not. If you not first of all install node and after installing it write the commands given below in order to install the packages that are listed above.

This command above is used to create the package.json file with the default options. After generating the package.json file we will now install the dependencies.

So here we are installing multiple dependencies with a space between them. And with the command npm install. And after it press enter it will take some time depending on the speed of the internet. After completion you will see the following package.json file with the dependencies inserted to it like this.

And after that we will now install the dev dependency nodemon which will restart the server for us automatically when we make any kind of changes to the application.

Now after successful of the nodemon package just go to the package.json and make these changes that are given below.

Instead of index.js just replace server.js as the main file. Secondly in the scripts section instead of the test write start and in the value write nodemon server.js. So we will write npm start and then it will start the nodemon package automatically.

Now we will create the server.js file which will be the starting point of the application. Here we will import all the dependencies that we have installed and also start the express server at port 5000.

const express = require('express'); const path = require('path'); const bodyParser = require('body-parser'); const expressHandlebars = require('express-handlebars'); var app = express(); app.listen(5000,() => { console.log("Serve is listening Port 5000"); })

Now we will run our application by just writing the below command npm start

When we open the browser at http://localhost:5000 we will seeing this error

This generally means that we didn’t configure the routes for our application. Now we will be configuring the routes in express application so just add this line to the server.js file.

app.get('/',(req,res) => { res.send("Hello world"); })

Configuring Body Parser Middleware

Now we will be configuring the middleware for our express application. First middleware will be body-parser. To configure this just write the below lines of code in server.js file. You have to write this code just after you have created the app variable.

app.use(bodyParser.urlencoded({ extended:true })); app.use(bodyParser.json());

Configuring Express Handlebars Middleware

Now we will be configuring the express-handlebars middleware this will be UI Building library for our express application. Just include right after you have included the body parser middleware.

app.set('views',path.join(__dirname,'/views/')) app.engine('hbs',expressHandlebars({ extname:'hbs', defaultLayout:'mainLayout', layoutsDir:__dirname + '/views/layouts/' })) app.set('view engine','hbs');

Here we are first of all setting the views of our application. We are setting a new directory for it which will be views directory. We will create this directory in the next step. But we have to define it first of all in order for the express application to recognize it. For finding the path we are using the path module that we have included earlier.

Now after that we are setting the engine of the application to be express-handlebars which has a extension of hbs. The first argument is the extension we are writing here ‘hbs’ and second argument will be the default Layout file which needs to be rendered when we start the application which is called mainLayout and here you don’t want to specify the extension of the file. And lastly we need to specify the layouts Directory of the application. In this directory we are using the __dirname and we will concatenate the /views/layouts/. There will be a new directory called as layouts which will be there inside the views directory. In the layouts directory we will be holding all the layouts of the application.

And lastly we are setting the view engine of the application i.e. ‘hbs’ handlebars. Through these lines of code we have successfully configured the express-handlebars library in the express application.

Downloading MongoDB Community Server

You can click this link to install the latest version of MongoDB Community Server which will also include the GUI Tool to manage the MongoDB Database called as Compass. I will be using this GUI Tool for rest of the application after downloading the exe file just follow the instructions and click next and next to install the MongoDB Server.

Creating the Database in MongoDB Compass

After you have installed Compass Tool Just open it this screen which is shown above will be there just click on the connect button. And then create the database

Our Database Name : EmployeeDB

Our Collection Name : employees

Connection to MongoDB in Application

Now we will be adding the MongoDB Database with the help of mongoose package which we have installed earlier on in the post.

Now create a new folder in the project folder called as models. Inside the models directory create a new file called as db.js which will hold the connection code which will made to the MongoDB Database.

const mongoose = require('mongoose'); const url = "mongodb://localhost:27017/EmployeeDB"; mongoose.connect(url,{useNewUrlParser:true},(err) => { if(!err){ console.log("MongoDB Connection Succeeded");} else{ console.log("An Error Occured"); } })

So in this section of code we are passing the url of the MongoDB and then we are using the mongoose package method of connect to actually make a connection to the database passing the required url and also passing a second parameter useNewUrlParser:true and a third parameter will be the callback function which will hold the error for us.If error takes place we are printing it on console. Or if connection is successful we are printing it on the console.

Now go to the server.js file to actually include this db.js file so that express server can recognize this file. Include it right at the top of the file like this

require('./models/db');

Now we run the application we will see the message displayed on the console i.e. MongoDB Connection succeeded like this

Adding Schema and Model to MongoDB

Now after making a connection to the database now we will be make the columns in the collection employees. For that we need to create a new file inside the views directory i.e. employee.model.js like this

const mongoose = require('mongoose'); var validator = require("email-validator"); var employeeSchema = new mongoose.Schema({ fullName:{ type:String, required: 'This field is required' }, email:{ type:String }, mobile:{ type:String }, city:{ type:String } }) // custom validation for email employeeSchema.path('email').validate((val) => { return validator.validate(val); },'Invalid Email'); mongoose.model('Employee',employeeSchema);

In this section of code we are first of all defining the schema for our collection employees which we have created earlier on. Our Application will contain four fields namely Full Name of the user, email address of the user, mobile number of the user, and city of the user. All the four fields are of type string. And the full name field have a additional attribute which is required set to true. This will force the users to write the Full Name strictly. And also we are using the path function to set some email validation on the email field. For this we are using the validate function to validate the email address. For this firstly we are importing the email-validator package right at the top of the file. And lastly we are creating the model named Employee by using this employeeSchema that we have defined in the file. And after you execute this code by running the server it will automatically create the collection structure containing four fields.

And lastly we need to include this model in the db.js file so that we can use this schema in the application. Just go to db.js file and write this line of code just at the bottom of the file like this

require('./employee.model');

Creating Views using Express-Handlebars

Now we will create the actual views or layout files that the user can see once they open the application. We already defined the default layout, layout directory and views directory all that stuff in the server.js file. Now create a directory called as views which will be holding all the views of the application.

Inside this views directory create a new directory called as layouts like this.

Inside the layouts directory create our default layout file called as mainLayout.hbs file which will contain all the default styles of the application like this

Inside this mainLayout.hbs we will writing some basic HTML Code which will rendering the default styles for the application. All the child views which we will create later on will inherit the styles defined in the file. So in this file first of all we will be importing bootstrap and font awesome library for making the icons. And lastly we will be setting a placeholder value in the triple curly brackets {{{body}}} and inside it we will write body variable. This generally means all the child views will be placed inside this variable. This is usually a concept of express-handlebars.

<!DOCTYPE html> <html> <head> <!-- Latest compiled and minified CSS --> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/css/bootstrap.min.css"> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"/> <title>Node.js Express MongoDB CRUD</title> <style> html,body{ height:100%; } </style> </head> <body class="bg-info"> <div class="row h-100 align-items-center"> <div style="margin-left:330px;background-color:white;margin-top:15px;padding:20px" class="col-md-6 offset-md-3"> {{{body}}} </div> </div> </body> </html>

And now create another directory called employee inside the views directory like this

Now this directory employee will hold all the views regarding the employee operation such as insertion or updation of the employee. Displaying the list of employees that are inserted into the database like this.

Just create a new file called addOrEdit.hbs inside it like this

Inside this addOrEdit.hbs file we have the h3 heading which contains a placeholder variable again called as viewTitle written in double curly brackets {{viewTitle}} we will passing the title dynamically when we configure routes so this value will be set according to the route the user is currently in. We will be having our Form which will be having the method set to post The form contain four fields full name , email , mobile and city and we will style the form using the bootstrap classes and also we will be having a button of submit in order to submit the form and also apart from that we will be also having a button to view all employees.

<h3>{{viewTitle}}</h3> <form action="/employee" method="POST" autocomplete="off"> <div class="form-group"> <label>Full Name</label> <input type="text" class="form-control" name="fullName" placeholder="Full Name"> </div> <div class="form-group"> <label>Email</label> <input type="email" class="form-control" name="email" placeholder="Email"> </div> <div class="form-row"> <div class="form-group md-6"> <label>Mobile</label> <input type="text" name="mobile" placeholder="Mobile" class="form-control"> </div> <div class="form-group md-6"> <label>City</label> <input type="text" name="city" placeholder="City" class="form-control"> </div> </div> <div class="form-group"> <button type="submit" class="btn btn-info"><i class="fa fa-database"></i>Submit</button> <a href="" class="btn btn-danger"> <i class="fa fa-list-alt"></i>View All </a> </div> </form>

Making the Employee Controller

Now we will be making the controller file for the Employee Model we have created earlier on. So Just create a new directory called controller and inside this directory we will create a new file called as employeeController.js

const express = require('express'); const router = express.Router(); router.get("/",(req,res) => { res.render("employee/addOrEdit",{ viewTitle:"Insert Employee" }) }) module.exports = router;

In this section of code we are first of all importing the express library. And in express library there is a function called Router which helps you to create routes. First of all we are creating the get route to the / which is generally equivalent to /employee as this is a employee controller. And after that we are rendering out the template that we have created with the express-handlebars earlier i.e. addOrEdit.hbs. This is will display the form to the user. And in the options we are passing the value of the viewTitle variable dynamically as Insert Employee as this will be insert employee form which will get populated to the user.

And lastly we are exporting the controller by module.exports = router line of code in order to include this controller in the server.js file.

Now go to the server.js file and include this controller file by having a new variable employeeController like this right at the top of the file

const employeeController = require('./controller/employeeController');

After including the controller and storing it in a variable we need to use it as a middleware like this at the bottom of the file

app.use('/employee',employeeController);

Now if you run the application once again by typing the url http://locahost:5000/employee you will see a form appearing allowing the users to enter the details and submit the form.

Inserting Employees into MongoDB Database

Now we will allow the users to actually write the data in the form and submit that data in the MongoDB Database. For that we need to handle a POST request which will be coming from this form. It’s action attribute is to /employee. So need to initiate a Post request to the following url / like this

// handling the post route of the form router.post("/",(req,res) => { insertRecord(req,res); })

Now we will create this custom function insertRecord(req,res) which takes two arguments request and response and it will actually save the employee model to the MongoDB Database. In order to import the model in the file first of all import the mongoose and employee model dependencies in the top of the file like this.

const mongoose = require('mongoose'); const Employee = mongoose.model('Employee');

After that we will be defining our insertRecord function like this

function insertRecord(req,res) { var employee = new Employee(); employee.fullName = req.body.fullName; employee.email = req.body.email; employee.city = req.body.city; employee.mobile = req.body.mobile; employee.save((err,doc) => { if(!err){ res.redirect('employee/list'); } else{ if(err.name == "ValidationError"){ handleValidationError(err,req.body); res.render("employee/addOrEdit",{ viewTitle:"Insert Employee", employee:req.body }) } console.log("Error occured during record insertion" + err); } }) }

In this section of code we are first of all importing the model Employee which we created earlier on based on the Schema we created of four fields. We are storing it in a vairable called employee and then we are setting the respective values i.e. firstname, email, mobile and city with the value entered by the user. We get the value that is entered by the user by the help of req.body.{{fieldname}}. And then we are invoking the save function on the model variable to actually save the model data into the MongoDB Database. This function takes a callback function which actually returns the error and the actual document which is being inserted. Firstly we are checking if there is no error then we are redirecting the user to the employee/list route which will list out all the employees which are inserted into the database. And if any kind of error is there we are checking for the error called as ValidationError then in that case we are calling a custom function called as handleValidationError(err,req.body) taking the actual error and req.body parameters. This is a custom function we will create now. And after that we are rendering the template called addOrEdit.hbs which will be the form again displayed to the user with the viewTitle equal to Insert Employee and another variable employee which will be equal to req.body.

Now we will define the handleValidationError function like this to check the errors for full name and email fields

function handleValidationError(err,body){ for(field in err.errors) { switch(err.errors[field].path){ case 'fullName': body['fullNameError'] = err.errors[field].message; break; case 'email': body['emailError'] = err.errors[field].message; break; default: break; } } }

Now we are embed these errors in the layout file called addOrEdit.hbs. So delete all the previous code which was there earlier on in the file and copy paste this fresh code given below.

<h3>{{viewTitle}}</h3> <form action="/employee" method="POST" autocomplete="off"> <input type="hidden" name="_id" value="{{employee._id}}"> <div class="form-group"> <label>Full Name</label> <input type="text" class="form-control" name="fullName" value="{{employee.fullName}}" placeholder="Full Name"> <div class="text-danger"> {{employee.fullNameError}} </div> </div> <div class="form-group"> <label>Email</label> <input type="email" class="form-control" name="email" value="{{employee.email}}" placeholder="Email"> <div class="text-danger"> {{employee.emailError}} </div> </div> <div class="form-row"> <div class="form-group md-6"> <label>Mobile</label> <input type="text" name="mobile" placeholder="Mobile" value="{{employee.mobile}}" class="form-control"> </div> <div class="form-group md-6"> <label>City</label> <input type="text" name="city" placeholder="City" value="{{employee.city}}" class="form-control"> </div> </div> <div class="form-group"> <button type="submit" class="btn btn-info"><i class="fa fa-database"></i>Submit</button> <a href="/employee/list" class="btn btn-danger"> <i class="fa fa-list-alt"></i>View All </a> </div> </form>

So you can see that in the template we are using the double braces symbol to embed the placeholder values for the value attribute and also for displaying the errors.

So now if we run the application at http://localhost:5000/employee and try to submit the form without entering the full name and email we get an error like this

Now if we write the details in the form like this

And try to submit the form we will get an error something like this as shown below

As you can see we are getting this error cannot get /employee/list because we haven’t created this get route for this url mentioned above. So we will be creating this in the next step. This will contain all the employees which are inserted in the database.

Now if you check the database you will see an entry has been added to the database with all the four fields first name ,email,mobile and city and one additional field is automatically being added which is the _id parameter which is actually is the primary key of the collection. We can uniquely select any record by it’s _id. It can’t be same for any record. We will be making use of it for updating and deleting operations.

So now to fix this error above. We will create a get route to the url /list to display all the employees which are present in the database alongside with their details.

// to view all the employees present in the database router.get('/list',(req,res) => { Employee.find((err,docs) => { if(!err) { res.render("employee/list",{ list:docs }) } }) })

So in this code we are fetching all the records which are present in the database. For this we are using the MongoDB find method to find all the records which is invoked on the employee model object. It takes the callback method which contains the error and the docs. If no error is present then we will be rendering the url employee/list. So list.hbs we haven’t created.

So just go to the employee directory present inside the views directory and create a new file list.hbs like this

<h3> <a href="/employee" class="btn btn-danger"> <i class="fa fa-plus"> </i> Create New </a> Employee List </h3> <table class="table table-striped"> <thead> <tr> <th>Full Name</th> <th>Email</th> <th>Mobile</th> <th>City</th> <th></th> </tr> </thead> <tbody> {{#each list}} <tr> <td>{{this.fullName}}</td> <td>{{this.email}}</td> <td>{{this.mobile}}</td> <td>{{this.city}}</td> <td> <a href=""> <i class="fa fa-pencil fa-lg" aria-hidden="true"></i> </a> <a href=""> <i class="fa fa-trash fa-lg" aria-hidden="true"> </i> </a> </td> </tr> {{/each}} </tbody> </table>

Here we are displaying all the details in a Bootstrap Table with table headings. In the table body we running a each loop in express handlebars to loop through all the array of employees which we have passed and in individual td tag we are displaying each user And lastly we have the update and delete icons for each row of employee.

If you run the application and once again go to http://localhost:5000/employee and click the view all button you will see the list of employees being displayed in the Table.

Updating the Employee Details

Now for updating the records we will be inserting a hidden field in the addOrEdit.hbs file. That hidden input field will include the _id parameter for the employee. This _id is actually the primary key of the collection. Through this _id we will be finding each employee by it’s unique number and then editing the details and updating it. Similar process will go for the delete process as well.

Go to the addOrEdit.hbs file and include the following line of code just after you have declared your form tag

<input type="hidden" name="_id" value="{{employee._id}}">

So now we will check if the _id field is set or not in the post route that we have defined in employeeController.js something like this

router.post("/",(req,res) => { if(req.body._id == "") { insertRecord(req,res); } else{ updateRecord(req,res); } })

So now if the _id field is not set then we know that this post request is for creating a new employee that is why we are calling the insertRecord function but if the _id field is set and has got some value then we know that this employee exists and this post request is to update the details of the employee then in this case we are calling the updateRecord function. This is again a custom function we will now create this to actually perform the update operation.

function updateRecord(req,res) { Employee.findOneAndUpdate({_id:req.body._id,},req.body,{new:true},(err,doc) => { if(!err){ res.redirect('employee/list'); } else{ if(err.name == "ValidationError") { handleValidationError(err,req.body); res.render("employee/addOrEdit",{ viewTitle:'Update Employee', employee:req.body }); } else{ console.log("Error occured in Updating the records" + err); } } }) }

In this section of code we are using the mongoose function called findOneAndUpdate function which takes four arguments first is the actual id field which you need to pass here we are fetching the id from the req.params.id and then the second argument is the actual data you need to update here in this case we are passing req.body. And the third argument is the new parameter which is set to true And lastly the fourth argument is the callback function which takes the error and doc variable. Firstly we check if no error is there then we are again redirecting the user to the employee/list url. But if any kind of error is there then we are again checking if it is validation error and if it is and then we are handling that errors respectively.

router.get('/:id',(req,res) => { Employee.findById(req.params.id,(err,doc) => { if(!err){ res.render("employee/addOrEdit",{ viewTitle: "Update Employee", employee: doc }) } }) })

Now we will write a get request passing the actual id parameter and then handling this request. In this first of all we are using the mongoose find by id method passing the actual id of the employee that the user has passed and then the second argument is the callback function which takes the error and doc which is a callback function first of all we check for the error if no error is there then we render out the form which is ’employee/addOrEdit’ but now we will update the viewTitle to update employee as this is the update form. and second argument will be the actual details of the actual employee which needs to be edited.

Now to complete this update operation we need to manipulate the href attribute of the button which is located in the list.hbs file we need to go to the pencil icon and update the href attribute like this as shown below.

<a href="/employee/{{this._id}}"> <i class="fa fa-pencil fa-lg" aria-hidden="true"></i> </a>

Now we if open the application once again click the edit pencil icon on the list of employees route we will see the update form appearing like this.

Deleting the Employee Operation

Now for deleting the record we will again use the hidden _id field which have declared in the previous step in order to delete the actual employee from the application and database.

First of all write a simple get route for deleting the employee by it’s _id field something like this. You have to write this in employeeController.js file.

router.get('/delete/:id',(req,res) => { Employee.findByIdAndRemove(req.params.id,(err,doc) => { if(!err){ res.redirect('/employee/list'); } else{ console.log("An error occured during the Delete Process" + err); } }) })

Now in the code we are passing the actual _id of the employee which needs to be deleted and then we are using the findByIdAndRemove method of mongoose and then passing the _id and second argument is the callback function which includes the error and the actual document which is deleted by this method and we are checking if no error is there then we are simply redirecting the user to the /employee/list route. And if any error is there then we are printing it in the console.

Now again go back to the list.hbs file and manipulate the href attribute of trash icon so that when we click it it should make this request. Apart from this we will also be binding a onclick event listener on that so that we can just populate a confirm window to the user asking that whether they really wanted to delete the item or not.

<a href="/employee/delete/{{this._id}}" onclick="return confirm('Are you sure to delete this record?');"> <i class="fa fa-trash fa-lg" aria-hidden="true"> </i> </a>

So Guys the application is complete now when we run the application and open the list route which will contain all the employees of the application. When we click the trash or dustbin icon we will be granted with a confirm window asking us to grant permission or not.