Node JS Mongoose CRUD application

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.

Mongoose official docs


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.

folder structure of the crud application

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:

Node JS MySQL Crud operations
Node MongoDB CRUD Operation

Leave a Reply

Your email address will not be published. Required fields are marked *