Learn how to perform CRUD with NodeJS Mongoose
In this tutorial, we are going to create a CRUD application using NodeJS and Mongoose ODM.
Mongoose is an Object Data Modeling (ODM) library commonly used in a Node.js application with a MongoDB database.
Mongoose provides a straight-forward, schema-based solution to model your application data.
It includes built-in typecasting, validation, query building, business logic hooks and more, out of the box.
To create this application follow the below steps
Step – 1
First, create a folder on your desktop and name it whatever you want, I call it app folder.
So, after that go inside the app folder and initialize npm by running the command npm init
Step – 2
Now you need to install some Node dependencies.
Here the list of all node dependencies which we’ll use to create our crud app.
- express (
npm install express --save
) - mongoose (
npm install mongoose --save
) - twig (
npm install twig --save
) - body-parser (
npm install body-parser --save
)
My package.json file
{
"name": "nodejs_mongoose",
"version": "1.0.0",
"description": "",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "webtutorials.me",
"license": "MIT",
"dependencies": {
"body-parser": "^1.18.3",
"express": "^4.16.4",
"mongoose": "^5.4.16",
"twig": "^1.13.2"
}
}
Files Creation
Before we’ll start to create our files late’s take a look at our app folder structure.

First, we’ll create our models. So, create a model folder inside the app folder.
Inside the model folder we just create one file it is post.js model
post.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const postSchema = new Schema({
title:{
type:String,
require:true
},
content:{
type:String,
require:true
},
author_name:{
type:String,
require:true
}
},{
timestamps: true
});
module.exports = mongoose.model('Post', postSchema);
After creating post.js model then we’ll create app.js file this is our main file.
app.js
const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const twig = require('twig');
const app = express();
const MONGODB_URL = 'mongodb://localhost:27017/mongoose';
const Post = require('./models/post');
// SET VIEW ENGINE and VIEWS
app.set('view engine', 'html');
app.engine('html', twig.__express);
app.set('views','views');
// APPLY BODY-PARSER MIDDLEWARE
app.use(bodyParser.urlencoded({extended:false}));
// HOME PAGE
app.get('/', (req, res) => {
// FETCH ALL POSTS FROM DATABASE
Post.find()
// SET descending ORDER BY createdAt
.sort({createdAt: 'descending'})
.then(result => {
if(result){
// RENDERING HOME VIEW WITH ALL POSTS
res.render('home',{
allpost:result
});
}
})
.catch(err => {
if (err) throw err;
});
});
// INSERT POST
app.post('/', (req, res) => {
new Post({
title:req.body.title,
content:req.body.content,
author_name:req.body.author
})
.save()
.then(result => {
res.redirect('/');
})
.catch(err => {
if (err) throw err;
});
});
// EDIT POST
app.get('/edit/:id', (req, res) => {
Post.findById(req.params.id)
.then(result => {
if(result){
res.render('edit',{
post:result
});
}
else{
res.redirect('/');
}
})
.catch(err => {
res.redirect('/');
});
});
// UPDATE POST
app.post('/edit/:id', (req, res) => {
Post.findById(req.params.id)
.then(result => {
if(result){
result.title = req.body.title;
result.content = req.body.content;
result.author_name = req.body.author;
return result.save();
}
else{
console.log(err);
res.redirect('/');
}
})
.then(update => {
res.redirect('/');
})
.catch(err => {
res.redirect('/');
});
});
// DELETE POST
app.get('/delete/:id', (req, res) => {
Post.findByIdAndDelete(req.params.id)
.then(result => {
res.redirect('/');
})
.catch(err => {
console.log(err);
res.redirect('/');
})
});
// IF DATABASE CONNECTION IS SUCCESSFULLY THEN RUN APP on PORT 3000
mongoose.connect(MONGODB_URL, {useNewUrlParser: true}).then(result => {
app.listen(3000);
}).catch(err => {
if (err) throw err;
});
Now we create our views. So, create a views folder inside our app folder.
Inside the views folder, we just create two views one is home.html and another edit.html.
home.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>NodeJS Mongoose CRUD App</title>
<style>
*{
box-sizing: border-box;
}
body{
padding: 50px;
margin: 0;
background: #f7f7f7;
font-family: sans-serif;
}
.container{
background-color: #ffffff;
padding: 10px;
margin: 0 auto;
max-width: 600px;
border: 1px solid #cccccc;
}
.insert_post input[type='text'],
.insert_post textarea{
width: 100%;
padding: 10px;
border: 1px solid #dddddd;
font-family: sans-serif;
margin-bottom: 5px;
font-size: 16px;
resize: vertical;
}
.insert_post label{
font-weight: bold;
}
h1,h2{
text-align: center;
text-transform: uppercase;
}
.insert_post input[type='text']:focus,
.insert_post textarea:focus{
outline: none;
border: 1px solid #cccccc;
}
.insert_post input[type='submit']{
padding: 10px 20px;
cursor: pointer;
background-color: #333333;
color: #ffffff;
outline: none;
border: 1px solid rgba(0,0,0,.1);
}
.insert_post input[type='submit']:hover{
background-color: #ffffff;
color: #222222;
border: 1px solid #333333;
}
/* SINGLE POST STYLING */
.single_post{
padding: 10px 0;
border-bottom: 1px solid #dddddd;
}
.single_post .post_title{
margin: 0 0 5px 0;
padding: 0;
}
.single_post .post_content{
margin: 5px 0;
padding: 0;
}
.single_post .post_info{
font-size: 14px;
}
.single_post .post_date{
color: #888888;
font-style: italic;
}
.post_actions{
padding-top: 5px;
}
.post_edit_btn,
.post_delete_btn{
border:1px solid rgba(0,0,0,.1);
outline: none;
text-decoration: none;
padding: 7px 15px;
display:inline-block;
}
.post_edit_btn{
background-color: #2c9f45;
color: #ffffff;
}
.post_delete_btn{
background-color: #ff4c4c;
color: #ffffff;
}
</style>
</head>
<body>
<div class="container">
<h1>Insert Post</h1>
<div class="insert_post">
<form action="" method="POST">
<label for="post_title">Post Title</label>
<input type="text" name="title" placeholder="Enter post title" id="post_title" required>
<label for="post_content">Write your post</label>
<textarea name="content" id="post_content" placeholder="Write something..." required></textarea>
<label for="author_name">Author Name</label>
<input type="text" name="author" placeholder="Enter author name" id="author_name" required>
<input type="submit" value="POST">
</form>
</div>
<hr>
<h2>Latest Updates</h2>
<div class="all_posts">
<!--
LEARN MORE ABOUT TWIG TEMPLATE ENGINE -
https://twig.symfony.com
-->
{% if allpost is empty %}
<h4>Not post found!</h4>
{% else %}
{% for post in allpost %}
<div class="single_post">
<h3 class="post_title">{{post.title | e}}</h3>
<div class="post_info"><span class="post_date">{{post.createdAt | date("d M, Y")}}</span> | <span class="post_author">By, <strong>{{post.author_name|e}}</strong></span></div>
<p class="post_content">{{post.content | e}}</p>
<div class="post_actions">
<a href="/edit/{{post._id}}" class="post_edit_btn">Edit</a> |
<a href="/delete/{{post._id}}" class="post_delete_btn">Delete</a>
</div>
</div>
{% endfor %}
{% endif %}
</div>
</div>
</body>
</html>
After creating home view now we’ll create edit view.
edit.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>NodeJS Mongoose CRUD App - Webtutorials.ME</title>
<style>
*{
box-sizing: border-box;
}
body{
padding: 50px;
margin: 0;
background: #f7f7f7;
font-family: sans-serif;
}
.container{
background-color: #ffffff;
padding: 10px;
margin: 0 auto;
max-width: 600px;
border: 1px solid #cccccc;
}
.insert_post input[type='text'],
.insert_post textarea{
width: 100%;
padding: 10px;
border: 1px solid #dddddd;
font-family: sans-serif;
margin-bottom: 5px;
font-size: 16px;
resize: vertical;
}
.insert_post label{
font-weight: bold;
}
h1,h2{
text-align: center;
text-transform: uppercase;
}
.insert_post input[type='text']:focus,
.insert_post textarea:focus{
outline: none;
border: 1px solid #cccccc;
}
.insert_post input[type='submit']{
padding: 10px 20px;
cursor: pointer;
background-color: #333333;
color: #ffffff;
outline: none;
border: 1px solid rgba(0,0,0,.1);
}
.insert_post input[type='submit']:hover{
background-color: #ffffff;
color: #222222;
border: 1px solid #333333;
}
/* SINGLE POST STYLING */
.single_post{
padding: 10px 0;
border-bottom: 1px solid #dddddd;
}
.single_post .post_title{
margin: 0 0 5px 0;
padding: 0;
}
.single_post .post_content{
margin: 5px 0;
padding: 0;
}
.single_post .post_info{
font-size: 14px;
}
.single_post .post_date{
color: #888888;
font-style: italic;
}
.post_actions{
padding-top: 5px;
}
.post_edit_btn,
.post_delete_btn{
border:1px solid rgba(0,0,0,.1);
outline: none;
text-decoration: none;
padding: 7px 15px;
display:inline-block;
}
.post_edit_btn{
background-color: #2c9f45;
color: #ffffff;
}
.post_delete_btn{
background-color: #ff4c4c;
color: #ffffff;
}
</style>
</head>
<body>
<div class="container">
<h1>Insert Post</h1>
<div class="insert_post">
<form action="" method="POST">
<label for="post_title">Post Title</label>
<input type="text" name="title" placeholder="Enter post title" id="post_title" value="{{post.title | e}}" required>
<label for="post_content">Write your post</label>
<textarea name="content" id="post_content" placeholder="Write something..." required>{{post.content | e}}</textarea>
<label for="author_name">Author Name</label>
<input type="text" name="author" placeholder="Enter author name" id="author_name" value="{{post.author_name | e}}" required>
<input type="submit" value="UPDATE">
</form>
</div>
</div>
</body>
</html>
Completed.
Learn also: