Building backend using NodeJS and MongoDB

Durga Gadiraju
itversity
Published in
14 min readJan 19, 2019

As part of this training we will understand basics of MongoDB and building backend for web applications using Node and Express along with Mongoose.

Agenda for the training

  • Setup Mongo
  • Overview of CLI
  • Basic CRUD Operations
  • Setup Datasets
  • Mongo Import
  • Mongo Queries
  • Aggregation Framework
  • Mongo Shell and Java Script
  • Indexing in MongoDB
  • Setup Node Project and Mongoose
  • Query Mongo DB Table using NodeJS
  • Basic CRUD Operations using NodeJS
  • Basic Queries using NodeJS
  • Aggregation Framework using NodeJS
  • Setup Express Project
  • Integrate Express with Mongoose
  • Modularize — Model, Controller and Route
  • CRUD Operations using Express

Setup Mongo

  • Download MongoDB
  • Install MongoDB
  • Start MongoDB Daemon
  • Validate by using mongo command

Overview of CLI

  • Launch mongo CLI
  • List Databases. Database is nothing but namespace for collections.
show dbs
  • List Collections. Collection is nothing but group of Documents. A Mongo Document is stored as BSON (Binary JSON).
show collections
  • A Document typically have column name and value. A value can be another Document or even array of values or array of Documents.
// Simple Document
{
"employeeNumber" : 1,
"firstName" : "Scott",
"lastName" : "Tiger"
}
// Nested Document
{
"employeeNumber" : 1,
"firstName" : "Scott",
"lastName" : "Tiger",
"department" : {
"departmentNumber" : 10,
"departmentName" : "Sales"
}
}
  • Connect to Database. We can use use command to switch to a Database. If Database does not exists, Database will be created when we create collection.
use demo
  • We can insert data by using insert on collection. If collection does not exists, it will be created when we insert first document.
db.employees.insert({ 
"employeeNumber" : 1,
"firstName" : "Scott",
"lastName" : "Tiger"
})
db.employees.findOne({})

Basic CRUD Operations

We will have a look at Basic CRUD Operations in Mongo DB using CLI. We will see more examples of querying after loading data into collections such as orders and orderItems.

  • Inserting Document (Create)
// By default system generated object will be assigned as _id which is unique
db.employees.insert({
"employeeNumber" : 2,
"firstName" : "Durga",
"lastName" : "Gadiraju",
"company" : "IT Versity, LLC.",
"age" : 30
})
db.employees.findOne({
"employeeNumber" : 2
})
// We can override objects in _id by the user defined values
db.employees.insert({
"_id" : 2,
"firstName" : "Durga",
"lastName" : "Gadiraju",
"company" : "IT Versity, LLC.",
"age" : 30
})
db.employees.find({
"_id" : 2
}).pretty()
  • Querying Document(s) (Read)
db.employees.find({}).pretty()db.employees.findOne({
"employeeNumber" : 2
})
  • Deleting Document(s) (Read and Delete)
db.employees.deleteOne({"_id" : 2})
db.employees.find({}).pretty()
  • Updating Document(s) (Read and Update). We can also upsert the data (Read and Insert or Update)
db.employees.update(
{"employeeNumber" : 2},
{"$set" : {"company" : "IT Versity, Inc."}}
)
db.employees.update(
{"employeeNumber" : 3},
{"$set" : {"company" : "IT Versity, Inc."}},
{"upsert" : true}
)

Setup Datasets

Let us go ahead and setup Datasets to play with realistic data to learn MongoDB.

  • Follow the instructions from this GitHub repository.
  • We will be using retail_db and retail_db_json directories.
  • Make sure to have the fully qualified path for retail_db and retail_db_json

Mongo Import

Mongo Import is the utility which can be used to load data into Mongo Collections.

  • You can review the details of mongoimport command by running it in command prompt.
mongoimport --help
  • We can load data from CSV or JSON format.
  • Field names can be specified or inferred from the first line of the input file. Check input options.
  • A new _id is created for each and every document.
  • We can overwrite existing collection or update data based on a key. Check ingest options.
mongoimport \
-h localhost \
--port=27017 \
--db=retail \
--collection=orders \
--type=csv \
--fields=order_id,order_date,order_customer_id,order_status \
--file=/Users/itversity/Research/data/retail_db/orders/part-00000
mongoimport \
-h localhost \
--port=27017 \
--db=retail \
--collection=orderItems \
--type=json \
--file=/Users/itversity/Research/data/retail_db_json/order_items/part-r-00000-6b83977e-3f20-404b-9b5f-29376ab1419e
  • Validate both orders and orderItems
use retail
db.orders.find({}).pretty()
db.orderItems.find({}).pretty()

Mongo Queries

Let us see some examples of querying data from Mongo Collections.

  • Make sure you are in the right database
  • Validate orders and orderItems
  • There are 2 functions to query data from collection, find and findOne. While find get all the records matching condition, findOne will get only the first record.
  • Find completed records.
use retail
db.orders.
find({"order_status" : "COMPLETE"}).
pretty()
db.orders.
findOne({"order_status" : "COMPLETE"})
  • Find all orders for month of 2014, January
db.orders.find({ "order_date" : /^2014-01/ }).pretty()
  • Find completed orders for month of 2014, January.
db.orders.find({ 
"order_date" : /^2014-01/,
"order_status" : "COMPLETE"
}).
pretty()
  • Find complete or closed orders for month of 2014, January.
db.orders.find({ 
"order_date" : /^2014-01/,
"$or" : [
{ "order_status" : "COMPLETE" },
{ "order_status" : "CLOSED" }
]
}).
pretty()
  • Find complete or closed orders for month of 2014, January using in operator.
db.orders.find({ 
"order_date" : /^2014-01/,
"order_status" : { "$in" : ["COMPLETE", "CLOSED"] }
}).
pretty()
  • Find complete orders and project only order_id, order_date and order_status. We need to disable _id, if it should not be projected.
db.orders.find(
{"order_status" : "COMPLETE"},
{"order_id" : 1, "order_date" : 1, "order_status" : 1, "_id" : 0}
)
db.orders.find(
{"order_status" : "COMPLETE"},
{"order_customer_id" : 0, "_id" : 0}
)

Aggregation Framework

Mongo DB have rich Aggregation Framework. Let us understand some important aspects of it.

  • Examples for Aggregation — sum, min, max, avg etc
  • Get count by order_status from orders
db.orders.aggregate([
{ "$group" :
{ "_id" : "$order_status",
"status_count" : { $sum : 1 }
}
}
])
  • Get revenue for order_item_order_id 2 from orderItems
db.orderItems.aggregate([
{ "$match" : { "order_item_order_id" : 2 }},
{ "$group" :
{ "_id" : "$order_item_order_id",
"order_revenue" : { "$sum" : "$order_item_subtotal" }
}
}
])
  • Get revenue for each order_item_order_id from orderItems
db.orderItems.aggregate([
{ "$group" :
{ "_id" : "$order_item_order_id",
"order_revenue" : { "$sum" : "$order_item_subtotal" }
}
}
])
  • Get revenue for each order_item_order_id from orderItems and project order_item_order_id (grouping key) as order_id.
db.orderItems.aggregate([
{ "$group" :
{ "_id" : "$order_item_order_id",
"order_revenue" : { "$sum" : "$order_item_subtotal" }
}
},
{ "$project" :
{ "order_item_order_id" : "$_id",
"_id" : 0,
"order_revenue" : 1
}
}
])

Mongo Shell and Java Script

We can write Java Script code as part of Mongo Shell. It executes synchronously. We cannot use this approach in Node as Node executes synchronously. We have to write code a bit differently to achieve this using NodeJS.

  • Create Connection
const mongoConnection = Mongo()
  • Create Database object
const retail = mongoConnection.getDB("retail")
  • Create collection object
const orders = retail.orders
  • Execute Query and Iterate through cursor
orders.find().forEach((order) => {
printjson(order)
})
  • Copy data from orders and orderItems to orderDetails (denormalized collection)
const mongoConnection = Mongo()
const retail = mongoConnection.getDB("retail")
const orders = retail.orders
const orderItems = retail.orderItems
orders.find().forEach((order) => { let orderDetails = order
let orderItemDetails = []
orderItems.
find({"order_item_order_id" : order.order_id}).
forEach((orderItem) => {
orderItemDetails.push(orderItem)
})
if(orderItemDetails.length != 0)
orderDetails['order_details'] = orderItemDetails
retail.orderDetails.insertOne(orderDetails)
})

Indexing in MongoDB

Let us discuss details with respect to Indexing in MongoDB.

  • By default data is indexed based on _id
  • Values in _id have to be unique
  • _id is of type Object and the value is system generated
  • We can assign custom values to _id, however, it need to be unique.
  • In MongoDB, we can index other columns as well.
  • In the previous Java Script program, we are iterating through orders and then looking up into orderItems using order_item_order_id. Once we look up into orderItems, we are inserting into orderDetails table.
  • As orderItems.order_item_order_id is not indexed, every time it have to perform full collection scan. We can speed up the performance by indexing orderItems.order_item_order_id.
db.orderItems.createIndex({"order_item_order_id" : 1})
db.orderItems.getIndexes()

Setup Node Project and Mongoose

First let us come up with simple NodeJS programs with Mongoose. For that we need to install Node and initialize simple Node project.

  • Install Node
  • Initialize Node Project
npm init
  • Install Mongoose
npm install -S mongoose

Query Mongo DB Table using NodeJS

First let us explore the steps required to insert data into Mongo DB collection using Java Script. We will be using mongoose plugin in simple Java Script program.

  • Install mongoose
npm install -S mongoose
  • Validate mongoose with simple Java Script program
  • Create file — findOrder.js
  • Create connection to MongoDB
const mongoose = require('mongoose');

const mongoDB = 'mongodb://localhost:27017/retail';
mongoose
.connect(mongoDB, { useNewUrlParser: true })
.catch((err) => {
throw err;
});
  • Define Schema
const OrderSchema = new mongoose.Schema({
order_id: Number,
order_date: String,
order_customer_id: Number,
order_status: String
});
  • Define Model
const OrderModel = mongoose.model('orders', OrderSchema);
  • Run find query
OrderModel
.findOne({ order_id: 1 })
.exec()
.then((order) => {
console.log(order);
mongoose.connection.close();
})
.catch((err) => {
mongoose.connection.close();
throw err;
});
  • Validate Program
node findOrder.js

Complete Code

const mongoose = require('mongoose');

const mongoDB = 'mongodb://localhost:27017/retail';
mongoose
.connect(mongoDB, { useNewUrlParser: true })
.catch((err) => {
throw err;
});

const OrderSchema = new mongoose.Schema({
order_id: Number,
order_date: String,
order_customer_id: Number,
order_status: String
});

const OrderModel = mongoose.model('orders', OrderSchema);

OrderModel
.findOne({ order_id: 1 })
.exec()
.then((order) => {
console.log(order);
mongoose.connection.close();
})
.catch((err) => {
mongoose.connection.close();
throw err;
});

Basic CRUD Operations using NodeJS

We will have a look at Basic CRUD Operations in Mongo DB using CLI. We will see more examples of querying after loading data into collections such as orders and orderItems.

  • Create connection to MongoDB
const mongoose = require('mongoose');

const mongoDB = 'mongodb://localhost:27017/retail';
mongoose
.connect(mongoDB, { useNewUrlParser: true })
.catch((err) => {
throw err;
});
  • Define Schema
const EmployeeSchema = new mongoose.Schema({
employeeNumber: Number,
firstName: String,
lastName: String,
company: String,
age: Number
});
  • Define Model
const EmployeeModel = mongoose.model('employees', EmployeeSchema);
  • Inserting Document (Create)
const employee = new EmployeeModel({
employeeNumber: 2,
firstName: 'Durga',
lastName: 'Gadiraju',
company: 'IT Versity, LLC.',
age: 30
});
employee
.save()
.then((employeeSaved) => {
console.log(employeeSaved);
})
.catch((err) => {
mongoose.connection.close();
throw err;
});
EmployeeModel
.find({ employeeNumber: 2 })
.exec()
.then((order) => {
console.log(order);
})
.catch((err) => {
throw err;
});
  • Querying Document(s) (Read)
EmployeeModel
.find({})
.exec()
.then((employees) => {
employees
.forEach(employeeRecord => console.log(employeeRecord));
})
.catch((err) => {
throw err;
});

EmployeeModel
.findOne({ employeeNumber: 2})
.exec()
.then((order) => {
console.log(order);
})
.catch((err) => {
throw err;
});
  • Deleting Document(s) (Read and Delete)
EmployeeModel
.deleteOne({ employeeNumber: 3 },
(err) => {
if (err) throw err;
});
EmployeeModel
.find({})
.exec()
.then((employees) => {
employees.forEach(employee => console.log(employee));
})
.catch((err) => {
if (err) throw err;
});
  • Updating Document(s) (Read and Update). We can also upsert the data (Read and Insert or Update). We have APIs such as update (deprecated), updateOne, updateMany etc.
const mongoose = require('mongoose');

const mongoDB = 'mongodb://localhost:27017/retail';
mongoose
.connect(mongoDB, { useNewUrlParser: true })
.catch((err) => {
throw err;
});
const EmployeeSchema = new mongoose.Schema({
employeeNumber: Number,
firstName: String,
lastName: String,
company: String,
age: Number
});

const EmployeeModel = mongoose.model('employees', EmployeeSchema);
const employee = new EmployeeModel({
employeeNumber: 2,
firstName: 'Durga',
lastName: 'Gadiraju',
company: 'IT Versity, LLC.',
age: 30
});

employee
.save()
.catch((err) => {
mongoose.connection.close();
throw err;
});

EmployeeModel
.find({ employeeNumber: 2 })
.exec()
.then((order) => {
console.log(order);
})
.catch((err) => {
throw err;
});

EmployeeModel
.updateOne(
{ employeeNumber: 2 },
{ $set: { company: 'IT Versity, Inc.' } },
(err) => {
if (err) throw err;
}
);

EmployeeModel
.find({ employeeNumber: 2 })
.exec()
.then((order) => {
console.log(order);
})
.catch((err) => {
throw err;
});

Basic Queries using NodeJS

  • Create connection to MongoDB
const mongoose = require('mongoose');

const mongoDB = 'mongodb://localhost:27017/retail';
mongoose
.connect(mongoDB, { useNewUrlParser: true })
.catch((err) => {
throw err;
});
  • Define Schema
const OrderSchema = new mongoose.Schema({
order_id: Number,
order_date: String,
order_customer_id: Number,
order_status: String
});
  • Define Model
const OrderModel = mongoose.model('orders', OrderSchema );
  • Find completed records.
OrderModel
.find({ order_status: 'COMPLETE' })
.exec()
.then((order) => {
console.log(order);
})
.catch((err) => {
throw err;
});
OrderModel
.findOne({ order_status: 'COMPLETE' })
.exec()
.then((order) => {
console.log(order);
})
.catch((err) => {
throw err;
});
  • orders for month of 2014, January
OrderModel
.find({ order_date: /^2014-01/ })
.exec()
.then((order) => {
console.log(order);
})
.catch((err) => {
throw err;
});
  • Find completed orders for month of 2014, January.
OrderModel
.find({
order_date: /^2014-01/,
order_status: 'COMPLETE'
})
.exec()
.then((order) => {
console.log(order);
})
.catch((err) => {
throw err;
});
  • Find complete or closed orders for month of 2014, January.
OrderModel
.find({
order_date: /^2014-01/,
$or: [
{ order_status: 'COMPLETE' },
{ order_status: 'CLOSED' }
]
})
.exec()
.then((order) => {
console.log(order);
})
.catch((err) => {
throw err;
});
  • Find complete or closed orders for month of 2014, January using in operator.
OrderModel
.find({
order_date: /^2014-01/,
order_status: { $in: [ 'COMPLETE', 'CLOSED' ] }
})
.exec()
.then((order) => {
console.log(order);
})
.catch((err) => {
throw err;
});
  • Find complete orders and project only order_id, order_date and order_status. We need to disable _id, if it should not be projected.
OrderModel
.find(
{ order_status: 'COMPLETE' },
{ order_id: 1,
order_date: 1,
order_status: 1,
_id: 0
})
.exec()
.then((order) => {
console.log(order);
})
.catch((err) => {
throw err;
});
OrderModel
.find(
{ order_status: 'COMPLETE' },
{ order_customer_id: 0, _id : 0 }
)
.exec()
.then((order) => {
console.log(order);
})
.catch((err) => {
throw err;
});

Aggregation Framework using NodeJS

Mongo DB have rich Aggregation Framework. Let us understand some important aspects of it.

  • Create connection to MongoDB
const mongoose = require('mongoose');

const mongoDB = 'mongodb://localhost:27017/retail';
mongoose
.connect(mongoDB, { useNewUrlParser: true })
.catch((err) => {
throw err;
});
  • Define Schema
const OrderSchema = new mongoose.Schema({
order_id: Number,
order_date: String,
order_customer_id: Number,
order_status: String
});
  • Define Model
const OrderModel = mongoose.model('orders', OrderSchema);
  • Examples for Aggregation — sum, min, max, avg etc
  • Get count by order_status from orders
OrderModel
.aggregate([
{
$group:
{
_id: '$order_status',
status_count: { $sum: 1 }
}
}
])
.exec()
.then((orderStatuses) => {
orderStatuses.forEach(orderStatus => console.log(orderStatus));
})
.catch((err) => {
mongoose.connection.close();
throw err;
});
  • Get revenue for order_item_order_id 2 from orderItems
const mongoose = require('mongoose');const mongoDB = 'mongodb://localhost:27017/retail';
mongoose
.connect(mongoDB, { useNewUrlParser: true })
.catch((err) => {
throw err;
});
const OrderItemSchema = new mongoose.Schema({
order_item_id: Number,
order_item_order_id: Number,
order_item_product_id: Number,
order_item_quantity: Number,
order_item_subtotal: Number,
order_item_product_price: Number
});
const OrderItemModel = mongoose.
model('orderItems', OrderItemSchema, 'orderItems');
OrderItemModel
.aggregate([
{ $match: { order_item_order_id: 2 } },
{
$group:
{
_id: '$order_item_order_id',
order_revenue: { $sum: '$order_item_subtotal' }
}
}
])
.exec()
.then((orderRevenue) => {
console.log(orderRevenue);
})
.catch((err) => {
throw err;
});
  • Get revenue for each order_item_order_id from orderItems
OrderItemModel
.aggregate([
{
$group:
{
_id: '$order_item_order_id',
order_revenue: { $sum: '$order_item_subtotal' }
}
}
])
.exec()
.then((orderRevenues) => {
orderRevenues
.forEach(orderRevenue => console.log(orderRevenue));
})
.catch((err) => {
throw err;
});
  • Get revenue for each order_item_order_id from orderItems and project order_item_order_id (grouping key) as order_id.
OrderItemModel
.aggregate([
{
$group:
{
_id: '$order_item_order_id',
order_revenue: { $sum: '$order_item_subtotal' }
}
},
{
$project:
{
order_item_order_id: '$_id',
_id: 0,
order_revenue: 1
}
}
])
.exec()
.then((orderRevenues) => {
orderRevenues
.forEach(orderRevenue => console.log(orderRevenue));
})
.catch((err) => {
throw err;
});

Setup Express Project

As we understand basics of Mongo, let us setup Node and Express so that we can explore the details related to building the application.

Why Express?

Setup Project using es6

We can setup express project using express-generator by following this link. However it will generate code using older version of Java Script.

  • es6 is latest version of Java Script.
  • There is no direct way of generating express project using es6. We need to use plugins called as yo and generator-express-es6.
  • Install yo globally.
npm install -g yo
  • Install generator-express-es6.
npm install -g generator-express-es6
  • Setup project using generator-express-es6.
yo express-es6// Project Name: retail
// Views: ejs
  • Validate Project Setup.
npm start

Integrate Express with Mongoose

Let us see how we can Integrate Express with Mongoose to access data from MongoDB.

  • We will be using HTTP GET request where we will be passing order id to get details of the order.

Steps to Integrate Express with Mongoose

In this we will update app.js to directly talk to MongoDB database and get order details for given order_id.

  • Import mongoose
const mongoose = require('mongoose');
  • Create connection to MongoDB
const mongoDB = 'mongodb://localhost:27017/retail';mongoose
.connect(mongoDB, { useNewUrlParser: true })
.catch((err) => {
throw err;
});
mongoose.Promise = global.Promise;
const db = mongoose.connection;

db.on('error', console.error.bind(console, 'MongoDB connection error:'));
  • Define Schema
const OrderSchema = new mongoose.Schema({
order_id: Number,
order_date: String,
order_customer_id: Number,
order_status: String
});

const OrderModel = mongoose.model('orders', OrderSchema, 'orders');
  • Provide logic to GET endpoint by passing order id
app.use('/orders/:id', (req, res) => {
OrderModel
.findOne({ order_id: req.params.id })
.exec()
.then((order) => {
res.send({ order });
});
});
  • Complete app.js
const cookieParser = require('cookie-parser');
const express = require('express');
const httpErrors = require('http-errors');
const logger = require('morgan');
const path = require('path');
const mongoose = require('mongoose');

const indexRouter = require('./routes/index');

const app = express();

const mongoDB = 'mongodb://localhost:27017/retail';
mongoose
.connect(mongoDB, { useNewUrlParser: true })
.catch((err) => {
throw err;
});
mongoose.Promise = global.Promise;
const db = mongoose.connection;

db.on('error', console.error.bind(console, 'MongoDB connection error:'));

const OrderSchema = new mongoose.Schema({
order_id: Number,
order_date: String,
order_customer_id: Number,
order_status: String
});

const OrderModel = mongoose.model('orders', OrderSchema, 'orders');

app.set('views', path.join(__dirname, 'views'));
// view engine setup
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());

app.use(express.static(path.join(__dirname, 'public')));

app.use('/', indexRouter);
app.use('/orders/:id', (req, res) => {
OrderModel
.findOne({ order_id: req.params.id })
.exec()
.then((order) => {
res.send({ order });
});
});

// catch 404 and forward to error handler
app.use((req, res, next) => {
next(httpErrors(404));
});

// error handler
app.use((err, req, res, next) => {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};

// render the error page
res.status(err.status || 500);
res.render('error');
});

module.exports = app;

Limitations

There are several limitations with the approach.

  • Code Manageability
  • Not modularized

Solution

Let us understand how we can modularize the code to overcome the limitations.

  • Create directories — models, controllers and add new file under routes
  • Create model
  • Create controller with functions for different HTTP end points (GET, POST, DELETE etc)
  • Define route for the main end point
  • Update app.js
  • Create connection and invoke route in app.js → Invoke function from controller → Develop logic by using model created under models

Let us start with creating directories — models and controllers

Modularize — Model, Controller and Route

Here are the steps to modularize Node and Express application for Mongo Integration.

Create Model

Let us add model to the application and refactor app.js to use the model.

  • Create ./models/OrderModel.js
const mongoose = require('mongoose');

const OrderSchema = new mongoose.Schema({
order_id: Number,
order_date: String,
order_customer_id: Number,
order_status: String
});

const OrderModel = mongoose.model('orders', OrderSchema, 'orders');

module.exports = OrderModel;
  • Import model in app.js and refactor to use OrderModel from ./models/OrderModel.js
const cookieParser = require('cookie-parser');
const express = require('express');
const httpErrors = require('http-errors');
const logger = require('morgan');
const path = require('path');
const mongoose = require('mongoose');

const indexRouter = require('./routes/index');
const OrderModel = require('./models/OrderModel');

const app = express();

const mongoDB = 'mongodb://localhost:27017/retail';
mongoose
.connect(mongoDB, { useNewUrlParser: true })
.catch((err) => {
throw err;
});
mongoose.Promise = global.Promise;
const db = mongoose.connection;

db.on('error', console.error.bind(console, 'MongoDB connection error:'));

app.set('views', path.join(__dirname, 'views'));
// view engine setup
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());

app.use(express.static(path.join(__dirname, 'public')));

app.use('/', indexRouter);
app.use('/orders/:id', (req, res) => {
OrderModel
.findOne({ order_id: req.params.id })
.exec()
.then((order) => {
res.send({ order });
});
});

// catch 404 and forward to error handler
app.use((req, res, next) => {
next(httpErrors(404));
});

// error handler
app.use((err, req, res, next) => {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};

// render the error page
res.status(err.status || 500);
res.render('error');
});

module.exports = app;

Add Controller

Let us add controller and refactor app.js to use the controller.

  • Create controllers/orderController.js — import model and develop function order_get for end point /orders/:id.
const OrderModel = require('../models/OrderModel');

function order_get(req, res) {
OrderModel
.findOne({ order_id: req.params.id })
.exec()
.then((order) => {
res.send({ order });
});
}

exports.order_get = order_get;
  • Update app.js — remove reference to model, import controller and invoke function order_get for end point /orders/:id
const cookieParser = require('cookie-parser');
const express = require('express');
const httpErrors = require('http-errors');
const logger = require('morgan');
const path = require('path');
const mongoose = require('mongoose');

const indexRouter = require('./routes/index');
const orderController = require('./controllers/orderController');

const app = express();

const mongoDB = 'mongodb://localhost:27017/retail';
mongoose
.connect(mongoDB, { useNewUrlParser: true })
.catch((err) => {
throw err;
});
mongoose.Promise = global.Promise;
const db = mongoose.connection;

db.on('error', console.error.bind(console, 'MongoDB connection error:'));

app.set('views', path.join(__dirname, 'views'));
// view engine setup
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());

app.use(express.static(path.join(__dirname, 'public')));

app.use('/', indexRouter);
app.use('/orders/:id', (req, res) => orderController.order_get(req, res));

// catch 404 and forward to error handler
app.use((req, res, next) => {
next(httpErrors(404));
});

// error handler
app.use((err, req, res, next) => {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};

// render the error page
res.status(err.status || 500);
res.render('error');
});

module.exports = app;

Add Router

Let us add router and refactor app.js to use router which will invoke controller.

  • Create router/orders.js — import controller and invoke function for end point GET id under orders.
const express = require('express');
const orderController = require('../controllers/orderController');

const router = express.Router();

router.get('/:id', orderController.order_get);

module.exports = router;
  • Update app.js — remove reference to controller, import router and invoke orderRouter for all end points under /orders.
const cookieParser = require('cookie-parser');
const express = require('express');
const httpErrors = require('http-errors');
const logger = require('morgan');
const path = require('path');
const mongoose = require('mongoose');

const indexRouter = require('./routes/index');
const orderRouter = require('./routes/orders');

const app = express();

const mongoDB = 'mongodb://localhost:27017/retail';
mongoose
.connect(mongoDB, { useNewUrlParser: true })
.catch((err) => {
throw err;
});
mongoose.Promise = global.Promise;
const db = mongoose.connection;

db.on('error', console.error.bind(console, 'MongoDB connection error:'));

app.set('views', path.join(__dirname, 'views'));
// view engine setup
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());

app.use(express.static(path.join(__dirname, 'public')));

app.use('/', indexRouter);
app.use('/orders', orderRouter);

// catch 404 and forward to error handler
app.use((req, res, next) => {
next(httpErrors(404));
});

// error handler
app.use((err, req, res, next) => {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};

// render the error page
res.status(err.status || 500);
res.render('error');
});

module.exports = app;

--

--