Node JS with MongoDB Atlas

Introduction

First of All if you haven’t check my previous post about NodeJS with Sequelize ORM better you check it first for better understanding about differences between Mongodb & MySQL.

MongoDB is an open source database management system (DBMS) that stores data in JSON-like formats. It is a highly scalable, flexible and distributed NoSQL database It is one of the most powerful NoSQL systems and databases around today. Being a NoSQL tool means it does not use the usual rows and columns that we so much associate with the relational database management.It allows documents to have different fields and structures. This database uses a document storage format called BSON which is a binary style of JSON style documents.

And What is Mongoose ? Mongoose is an object data modeling (ODM) library that provides a rigorous modeling environment for your data, enforcing structure as needed while still maintaining the flexibility that makes MongoDB powerful it is like Sequlize in MySQL the difference is mongoose is for mongodb.

Project Intro

Let’s straight to the point , today i’,m gonna build same project like previous post simple CRUD App in this case is fruit shop with mongodb Atlas+Mongoose,yes the cloud is here! and this is technology and tools i use for :

TechnologyName
Back EndNodeJS
FrameworkExpress & Bootstrap 4
DBMSMongodb Atlas
NPMMongodb & Body Parser & Nodemon & Mongoose
Template EngineEJS
Develop Step

First, Create Mongodb Atlas Account & Create a Cluster, Remember we build database with Atlas it’s mean Mongodb in the Cloud ! For that mongodb give us very clear documentation.link down below.

Second create Folder and then Npm init

Next Install All Npm Package above

  • npm install –save nodemon
  • npm install –save express
  • npm install –save mongoose
  • npm install –save ejs

Next ,Create MVC folder schema it’s up to you for name but this is mine :

  • controller
  • models
  • routes
  • views
    • includes

Next Create server & database connection ,require all package from app.js (our main route). Important please use your MongoDB Atlas string and fill it with your password. :

//Software Engineer : Faeshal Bin Sulaiman const path = require("path");
const express = require("express");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const adminRoutes = require("./routes/admin");
const app = express();

app.set("view engine", "ejs");
app.set("views", "views");
app.use(bodyParser.urlencoded({ extended: false }));
app.use(adminRoutes);

mongoose
  .connect(
    "mongodb+srv://:@clusterfruit-gtqj8.mongodb.net/shop?retryWrites=true"
  )
  .then(result => {
    app.listen(3000);
  })
  .catch(err => {
    console.log(err);
  });

Next the most important create controller name admin.js inside controller folder.Controller use for connect model and view and bring functionality

const Product = require("../models/product");

exports.getAddProduct = (req, res, next) => {
  res.render("add", {
    pageTitle: "Add Product",
    path: "/add",
    editing: false
  });
};

exports.postAddProduct = (req, res, next) => {
  const title = req.body.title;
  const imageUrl = req.body.imageUrl;
  const price = req.body.price;
  const stock = req.body.stock;
  const description = req.body.description;
  const product = new Product({
    title: title,
    imageUrl: imageUrl,
    price: price,
    stock: stock,
    description: description
  });
  product
    .save()
    .then(result => {
      console.log("Created Product");
      res.redirect("/");
    })
    .catch(err => {
      console.log(err);
    });
};

exports.getEditProduct = (req, res, next) => {
  const editMode = req.query.edit;
  if (!editMode) {
    return res.redirect("/");
  }
  const prodId = req.params.productId;
  Product.findById(prodId)
    .then(product => {
      if (!product) {
        return res.redirect("/");
      }
      res.render("edit", {
        pageTitle: "Edit Product",
        path: "/edit",
        editing: editMode,
        product: product
      });
    })
    .catch(err => console.log(err));
};

exports.postEditProduct = (req, res, next) => {
  const prodId = req.body.productId;
  const updatedTitle = req.body.title;
  const updatedPrice = req.body.price;
  const updatedStock = req.body.stock;
  const updatedImageUrl = req.body.imageUrl;
  const updatedDesc = req.body.description;

  Product.findById(prodId)
    .then(product => {
      product.title = updatedTitle;
      product.price = updatedPrice;
      product.stock = updatedStock;
      product.description = updatedDesc;
      product.imageUrl = updatedImageUrl;
      return product.save();
    })
    .then(result => {
      console.log("UPDATED PRODUCT!");
      res.redirect("/");
    })
    .catch(err => console.log(err));
};

exports.getProducts = (req, res, next) => {
  Product.find()
    .then(products => {
      res.render("index", {
        prods: products,
        pageTitle: "Admin Products",
        path: "/"
      });
    })
    .catch(err => console.log(err));
};

exports.postDeleteProduct = (req, res, next) => {
  const prodId = req.body.productId;
  Product.findByIdAndRemove(prodId)
    .then(() => {
      console.log("Delete Succesfull");
      res.redirect("/");
    })
    .catch(err => console.log(err));
};

Next create admin.js again inside routes folder and create routing & call from controller

const express = require("express");
const adminController = require("../controller/admin");
const router = express.Router();

router.get("/add", adminController.getAddProduct);
router.get("/", adminController.getProducts);
router.post("/add", adminController.postAddProduct);
router.get("/edit/:productId", adminController.getEditProduct);
router.post("/edit", adminController.postEditProduct);
router.post("/delete", adminController.postDeleteProduct);

module.exports = router;

Next , Create product.js inside models folder for manage database structure

const mongoose = require("mongoose");
const Schema = mongoose.Schema;

const productSchema = new Schema({
  title: {
    type: String,
    required: true
  },
  price: {
    type: Number,
    required: true
  },
  imageUrl: {
    type: String,
    required: true
  },
  stock: {
    type: Number,
    required: true
  },
  description: {
    type: String,
    required: true
  }
});

module.exports = mongoose.model("Product", productSchema);

Next we build the view. I will separate header and footer inside views/includes for use by 3 main file inside views which is index.ejs(for main page),add.ejs(for add product page),edit.ejs(for edit product).So this is good for modularity and clean code. Ok this is head.ejs inside views/includes:

<!DOCTYPE html>
    <html lang="en">
      <head>
        <title>Fruit App</title>
        <!-- Required meta tags -->
        <meta charset="utf-8" />
        <meta
          name="viewport"
          content="width=device-width, initial-scale=1, shrink-to-fit=no"
        />

        <!-- Bootstrap CSS -->
        <link
          rel="stylesheet"
          href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
          integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"
          crossorigin="anonymous"
        />
      <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css" integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf" crossorigin="anonymous"></link>
      </head>
      <body>

        <!-- NAVBAR -->
      <nav class="navbar navbar-light bg-light">
        <a class="navbar-brand" href="/">
        <i class="fas fa-campground d-inline-block align-top mr-2 ml-2 mt-1 fa-lg"></i>
        Shop</a>
        <a class="navbar-brand ml-auto" href="/add"><i class="fas fa-plus"></i></i></a>
        <a class="navbar-brand ml-auto" href="https://www.instagram.com/faeshal_/" target="_blank"><i class="fab fa-instagram fa-lg"></i></a>
        <a class="navbar-brand" href="https://github.com/faeshal" target="_blank"><i class="fab fa-github fa-lg"></i></a>
      </nav>

and this is the end.ejs

<!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <script
      src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
      integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
      crossorigin="anonymous"
    ></script>
    <script
      src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"
      integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1"
      crossorigin="anonymous"
    ></script>
    <script
      src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
      integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM"
      crossorigin="anonymous"
    ></script>
  </body>
</html>

And the main view , index.ejs

<%-include("includes/head.ejs")%>
    <!-- SECTION: CONTENT -->
    <div class="container mb-2 mt-4">
      <h4 class="text-center mb-4">FRUITS</h4>
      <hr />
      <!-- SECTION : CARD -->
      <div class="row text-center">
        <% if (prods.length > 0) { %> <% for (let product of prods) { %>
        <div class="col-md-4 text-center ">
          <div class="card mb-4 mt-2 mr-4 ml-4 mx-auto" style="width: 17rem;">
            <h5 class="card-title text-center mt-2 mb-2"><%-product.title%></h5>
            <img
              class="card-img-top"
              src="<%-product.imageUrl%>"
              alt="Card image cap"
            />
            <div class="card-body text-center">
              <h5 class="card-title">$ <%-product.price%></h5>
              <h6 class="text-muted"><%-product.stock%> Stock</h6>
              <p class="card-text">
                <%-product.description%>
              </p>

              <form id="myForm" method="POST" action="/delete">
                <a
                  href="/edit/<%= product._id %>?edit=true"
                  class="btn btn-warning mr-3"

                  >Update</a
                >
                <input type="hidden" value="<%= product._id %>" name="productId" />
                <button
                  class="btn btn-danger"
                  onclick="return confirm('Are You Sure?');"
                >
                  Delete
                </button>
              </form>
            </div>
          </div>
        </div>
        <% } %>

        <!-- END CARD -->
        <% } else { %>
        <h6 class="text-center">No Product</h6>
        <% } %>
      </div>
    </div>
    <!--  -->

    <%-include("includes/end.ejs")%>

This is Add.ejs

  <%-include("includes/head.ejs")%>
    <!-- SECTION:CONTENT -->
    <div class="container" class="mt-4 ml-2 mr-2">
      <h4 class="text-center mt-4">ADD PRODUCTS</h4>
      <hr />
      <div class="row">
        <div class="col-sm-10 mx-auto">
          <form action="/add" method="POST">
            <div class="form-group mt-4">
              <input
                type="text"
                name="title"
                class="form-control"
                id="title"
                aria-describedby="title"
                placeholder="Name"
              />
            </div>
            <div class="form-group">
              <input
                type="text"
                class="form-control"
                name="imageUrl"
                id="imageUrl"
                placeholder="Image Url"
              />
            </div>
            <div class="form-group">
              <input
                type="number"
                class="form-control"
                name="price"
                id="price"
                placeholder="Price"
              />
            </div>
            <div class="form-group">
              <input
                type="number"
                class="form-control"
                name="stock"
                id="stock"
                placeholder="Stock"
              />
            </div>
            <div class="form-group">
              <textarea
                class="form-control"
                name="description"
                id="description"
                rows="3"
                ,
                placeholder="Description"
              ></textarea>
            </div>
            <div class="text-center">
              <button type="submit" class="btn btn-outline-success btn-lg">
                Submit
              </button>
            </div>
          </form>
        </div>
      </div>
    </div>

    <!--  -->
    <%-include("includes/end.ejs")%>

This is Edit.ejs

  <%-include("includes/head.ejs")%> <
    <!-- SECTION:CONTENT -->
    <div class="container" class="mt-4 ml-2 mr-2">
      <h4 class="text-center mt-4">EDIT PRODUCTS</h4>
      <hr>
      <div class="row">
          <div class="col-sm-10 mx-auto">
      <form action="/edit" method="POST">
        <input type="hidden" value="<%= product._id %>" name="productId" />
        <div class="form-group mt-4">
          <input
            type="text"
            class="form-control"
            id="title"
            name="title"
            value="<%= product.title %>"
            aria-describedby="emailHelp"
          />
        </div>
        <div class="form-group">
          <input
            type="text"
            class="form-control"
            id="imageUrl"
            name="imageUrl"
            value="<%= product.imageUrl %>"
            aria-describedby="emailHelp"
          />
        </div>
        <div class="form-group">
          <input
            type="number"
            class="form-control"
            id="price"
            name="price"
            value="<%= product.price %>"
            aria-describedby="emailHelp"
          />
        </div>
        <div class="form-group">
          <input
            type="text"
            class="form-control"
            id="stock"
            name="stock"
            value="<%= product.stock %>"
            aria-describedby="emailHelp"
          />
        </div>
        <div class="form-group">
          <textarea
            class="form-control"
            name="description"
            id="description"
            rows="3"
            placeholder="Description"
          >
    <%= product.description %></textarea
          >
        </div>
        <div class="text-center">
          <button
            id="update"
            class="btn btn-outline-warning btn-lg"
            onclick="Update()"
            value="UPDATE"
          >
            UPDATE
          </button>
        </div>
    </div>
    </div>
    </div>

    <!--  -->
    <%-include("includes/end.ejs")%>
Result

Anyway you can create your own design for example the card and navbar with your style for sure, dont forget to npm start  for start the server . This is my result:

Let’s Try add Functionality :

This is Edit Functionality

And the last Delete functionality with destroy method ini Express

You can check your data for ensure your data push to the MongoDB Atlas.

Last Word

Hope you understand the Important thing is you know the differences work flow using MySQL and MongoDB so you can pick one DBMS that fit with your project requirement . Dont forget to check documentation for details as always link down below.