Image Uploading to MongoDb in Nodejs using Multer

In this tutorial, we are gonna use the Multer Library for uploading the image. The image uploading feature is used in so may production sites like social media, e-commerce site etc.

What is Multer?

⇒Multer is node js middleware used to handle multipart/form-data which is primarily used for uploading the files. The image can be saved in a buffer format in the database.

Schema for Image

  • Create a new Schema for images and pass the following parameters.
  • Set the data to buffer as the image will be uploaded in the buffer string the contentType will be a string.
  • Require the Mongoose and connect to the database.
var imgSchema = mongoose.Schema({
    img:{data:Buffer,contentType: String}
});

var image = mongoose.model("image",imgSchema);

MongoDB actually stores buffer in a special binary class. A MongoDB binary is just a wrapper around a buffer with an additional sub_type property. When we declare a mongoose schema type as a buffer, so Mongoose cast a buffer on its own.

Disk Storage

As the image will be uploaded in the database the developer does not have full control. Hence multer provides the option to save the file/image in disk storage.

  • Diskstorage function of multer is used to store images/file to disk
  • It is passed with two options
    • destination:-  Where the file is gonna store if it is not passed then file/image will be stored in systems default folders a callback is passed as well to execute.
    • filename:- It determines the file name that is about to be stored in the destination along with the callback which concatenates the name of a file to date at which it is saved.
  • The is stored in a variable for the displaying purpose.
var storage = multer.diskStorage({
    destination: function (req, file, cb) {
      cb(null, 'uploads')
    },
    filename: function (req, file, cb) {
      cb(null, file.fieldname + '-' + Date.now())
    }
  })

  var upload = multer({ storage: storage })

 Upload form

  • In the views, directory create a basic HTML file
  • The file consist upload form and button to submit
  • The enctype must be multipart/form-data.
  • Set the action as “/uploadphoto” which will be our route and Method to “POST” as the user has to upload the data.

Code:-

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>Upload Image</h1>
    <form action="/uploadphoto" enctype="multipart/form-data" method="POST">
        <input type="file" name="myImage" accept="image/*">
        <input type="submit" value="Upload Photo">
    </form>
</body>
</html>

enctype=’multipart/formdata is an encoding type that allows files to be sent through a POST. Quite simply, without this encoding, the files cannot be sent through POST. If you want to allow a user to upload a file via a form, you must use this enctype.

When user will click on select file a window will open which will be defaulted to select images.

Upload Logic and Setting up Routes

  • Set a get request for home page route or index route
  • Set a post route to “/uploadphoto” use middleware upload.single(‘myImage’)
  • Give a callback function and save the image in a variable.
  • Use that variable to encode the image to base64 string and pass that to an object of imageschema created earlier.
  • Then use create a function with a callback saving the image to the database as well.
//Routes
app.get("/",(req,res)=>{
    res.render("index");
})


app.post("/uploadphoto",upload.single('myImage'),(req,res)=>{
    var img = fs.readFileSync(req.file.path);
    var encode_img = img.toString('base64');
    var final_img = {
        contentType:req.file.mimetype,
        image:new Buffer(encode_img,'base64')
    };
    image.create(final_img,function(err,result){
        if(err){
            console.log(err);
        }else{
            console.log(result.img.Buffer);
            console.log("Saved To database");
            res.contentType(final_img.contentType);
            res.send(final_img.image);
        }
    })
})

Note:- Image cannot be directly saved in a database they have to be encoded in equivalent buffer string and then can be passed and stored in the database. Hence we use function tosring(‘base64’).

⇒When Image is uploaded it saves in the database in the given form.

Setup App.js

  • Require all dependencies in the file
  • Set up the express server and port.
  • Connect to database
  • Add all the above files and start the server
    const express = require("express"),
          app = express(),
          bodyParser = require("body-parser"),
          fs = require("fs"),
          multer = require("multer"),
          mongoose = require("mongoose");
    
    mongoose.connect("mongodb://localhost/Images");      
    app.use(bodyParser.urlencoded(
          { extended:true }
    ))
    app.set("view engine","ejs");
    
    //Schema
    var imgSchema = mongoose.Schema({
        img:{data:Buffer,contentType: String}
    });
    
    var image = mongoose.model("image",imgSchema); 
    
    // SET STORAGE
    var storage = multer.diskStorage({
        destination: function (req, file, cb) {
          cb(null, 'uploads')
        },
        filename: function (req, file, cb) {
          cb(null, file.fieldname + '-' + Date.now())
        }
      })
    
      var upload = multer({ storage: storage })
    
      //Routes
    app.get("/",(req,res)=>{
        res.render("index");
    });
    
    app.post("/uploadphoto",upload.single('myImage'),(req,res)=>{
        var img = fs.readFileSync(req.file.path);
        var encode_img = img.toString('base64');
        var final_img = {
            contentType:req.file.mimetype,
            image:new Buffer(encode_img,'base64')
        };
        image.create(final_img,function(err,result){
            if(err){
                console.log(err);
            }else{
                console.log(result.img.Buffer);
                console.log("Saved To database");
                res.contentType(final_img.contentType);
                res.send(final_img.image);
            }
        })
    })
    
    
    //Code to start server
    app.listen(2000,function () {
          console.log("Server Started at PORT 2000");
    })