📖
Maissen's Grimoire
  • Maissen's Grimoire
  • Html and css grimoire
    • HTML5 Periodical Table
    • HTML Cheat Sheet
    • CSS Cheatsheets
  • Javascript Grimoire
    • JavaScript Cheat Sheet
      • Javascript Array in depth
      • Tagged Template Literals
      • Guard Clauses - The Best Way To Write Complex Conditional Logic
      • JavaScript Optional Chaining
      • JavaScript Null Coalesce
      • What Are Magic Numbers And Why Are They Bad
      • ES6/ECMAScript2015 Cheatsheet
      • First-class and Higher Order Functions: Effective Functional JavaScript
    • Useful JavaScript Tips, Tricks and Best Practices
    • Bits of code
    • Useful JavaScript libraries
      • Components
      • Animation
      • Maps
      • Helpers
      • Presentations
      • Charts
      • Games
      • Audio
      • Images
      • Video
    • Js the right way
  • Angular Grimoire
    • Angular doc
    • Getting Started
    • Angular clean architecture
    • Angular Cheat Sheet
    • TypeScript Cheat Sheet
    • My Favorite Tips and Tricks in Angular
    • NgRx: tips & tricks
    • Bits of code
      • Execute Multiple HTTP Requests in Angular
      • Authentification
        • Angular 8 JWT Authentication with HttpInterceptor and Router
      • Integrations
        • Spring Boot
          • Rest Example
            • Angular,Spring Boot,Spring Data and Rest Example(CRUD)
          • Authentification
            • Angular, Spring Boot: JWT Authentication with Spring Security example
            • Angular Spring Boot Security Oauth2
              • Spring Boot OAUTH2 Role-Based Authorization
              • Spring Boot Security Google Oauth
              • Spring Security OAuth2 User Registration
    • Most used dependency
  • Node Grimoire
    • Express.js 4 Cheatsheet
    • Useful Dependencies
    • How To Use And Write Express Middleware
    • Node.js with SQL databases
      • Node.js Token Based Authentication & Authorization example
      • Node.js Rest APIs example with Express, Sequelize & MySQL
      • Node.js Express & PostgreSQL: CRUD Rest APIs example with Sequelize
      • Sequelize
        • Sequelize Many-to-Many Association example – Node.js & MySQL
        • Sequelize One-to-Many Association example with Node.js & MySQL
    • Node.js with NOSQL databases
      • Node.js + MongoDB: User Authentication & Authorization with JWT
      • Node.js, Express & MongoDb: Build a CRUD Rest Api example
      • MongoDB One-to-One relationship tutorial with Mongoose example
      • MongoDB One-to-Many Relationship tutorial with Mongoose examples
      • MongoDB Many-to-Many Relationship with Mongoose examples
  • Upload files
    • How to upload multiple files in Node.js
    • Upload & resize multiple images in Node.js using Express, Multer, Sharp
    • Upload/store images in MySQL using Node.js, Express & Multer
    • How to upload/store images in MongoDB using Node.js, Express & Multer
  • React Grimoire
    • React Doc
    • React Grimoire
    • React Cheat Sheet
  • spring boot Grimoire
    • Getting started
    • Spring Boot, Spring Data JPA – Rest CRUD API example
    • Spring Boot Token based Authentication with Spring Security & JWT
  • Mongo Grimoire
    • MongoDb-Mongoose Cheat Sheet
  • Development tools
    • Design Patterns
  • maissen_grimoire
Powered by GitBook
On this page
  • Node.js upload/store image in MongoDB
  • Node.js upload/store multiple images in MongoDB

Was this helpful?

  1. Upload files

How to upload/store images in MongoDB using Node.js, Express & Multer

PreviousUpload/store images in MySQL using Node.js, Express & MulterNextReact Cheat Sheet

Last updated 5 years ago

Was this helpful?

Node.js upload/store image in MongoDB

We’re gonna show you how to build this Node.js app step by step.

Project Structure

Now look at our project structure:

node-js-upload-store-images-mongodb-project-structure-revise

– views/index.html: contains HTML form for user to upload images. – routes/web.js: defines routes for endpoints that is called from views, use controllers to handle requests. – controllers:

  • home.js returns views/index.html

  • upload.js handles upload & store images with middleware function.

– middleware/upload.js: initializes Multer GridFs Storage engine (including MongoDB) and defines middleware function. – server.js: initializes routes, runs Express app.

Setup Node.js modules

Open command promt, change current directory to the root folder of our project. Install Express, Multer, Multer GridFs Storage with the following command:

npm install express multer multer-gridfs-storage

The package.json file will look like this:

{
  "name": "upload-multiple-files",
  "version": "1.0.0",
  "description": "Node.js upload multiple files Demo",
  "main": "server.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "node",
    "upload",
    "multiple",
    "files"
  ],
  "author": "bezkoder",
  "license": "ISC",
  "dependencies": {
    "express": "^4.17.1",
    "multer": "^1.4.2",
    "multer-gridfs-storage": "^4.0.1"
  }
}

Create View for uploading image

In views folder, create index.html file with the HTML and Javascript code as below:

<!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>Node.js upload images</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" />
    <style>
      div.preview-images > img {
        width: 30%;
      }
    </style>
  </head>

  <body>
    <div class="container">
      <div class="row">
        <div class="col-sm-8 mt-3">
          <h4>Node.js upload images - bezkoder.com</h4>

          <form class="mt-4"
            action="/upload"
            method="POST"
            enctype="multipart/form-data"
          >
            <div class="form-group">
              <input
                type="file"
                name="file"
                id="input-files"
                class="form-control-file border"
              />
            </div>
            <button type="submit" class="btn btn-primary">Submit</button>
          </form>
        </div>
      </div>
      <hr />
      <div class="row">
        <div class="col-sm-12">
          <div class="preview-images"></div>
        </div>
      </div>
    </div>

    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.bundle.min.js"></script>
    <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
    <script>
      $(document).ready(function() {
        let imagesPreview = function(input, placeToInsertImagePreview) {
          if (input.files) {
            let filesAmount = input.files.length;
            for (i = 0; i < filesAmount; i++) {
              let reader = new FileReader();
              reader.onload = function(event) {
                $($.parseHTML("<img>"))
                  .attr("src", event.target.result)
                  .appendTo(placeToInsertImagePreview);
              };
              reader.readAsDataURL(input.files[i]);
            }
          }
        };
        $("#input-files").on("change", function() {
          imagesPreview(this, "div.preview-images");
        });
      });
    </script>
  </body>
</html>

For HTML part, we create a form with following elements:

  • action="/upload"

  • method="POST"

  • enctype="multipart/form-data"

You also need to notice the input tag with the name="file" attribute that we will use in the middleware.

The jQuery script shows preview of the chosen images. We also use Bootstrap to make the UI more comfortable to read.

Create middleware for uploading & storing image

Inside middleware folder, create upload.js file with the following code:

const util = require("util");
const multer = require("multer");
const GridFsStorage = require("multer-gridfs-storage");

var storage = new GridFsStorage({
  url: "mongodb://localhost:27017/bezkoder_files_db",
  options: { useNewUrlParser: true, useUnifiedTopology: true },
  file: (req, file) => {
    const match = ["image/png", "image/jpeg"];

    if (match.indexOf(file.mimetype) === -1) {
      const filename = `${Date.now()}-bezkoder-${file.originalname}`;
      return filename;
    }

    return {
      bucketName: "photos",
      filename: `${Date.now()}-bezkoder-${file.originalname}`
    };
  }
});

var uploadFile = multer({ storage: storage }).single("file");
var uploadFilesMiddleware = util.promisify(uploadFile);
module.exports = uploadFilesMiddleware;

– We define a storage configuration object with GridFsStorage class.

  • url: must be a standard MongoDB connection string pointing to the MongoDB database. multer-gridfs-storage module will create a mongodb connection for you automatically.

  • file: this is the function to control the file storage in the database. The return value of this function is an object with the properties such as: filename, metadata, chunkSize, bucketName, contentType… We also check if the file is an image or not using file.mimetype. Then we add the [timestamp]-bezkoder- prefix to the file’s original name to make sure that the duplicates never occur in MongoDB collection. bucketName indicates that the file will be stored at photos.chunks and photos.files collections.

– Next we use multer module to initialize middleware and util.promisify() to make the exported middleware object can be used with async-await.

Create Controller for the view

controllers/home.js

const path = require("path");

const home = (req, res) => {
  return res.sendFile(path.join(`${__dirname}/../views/index.html`));
};

module.exports = {
  getHome: home
};

Create Controller for uploading Images

controllers/upload.js

const upload = require("../middleware/upload");

const uploadFile = async (req, res) => {
  try {
    await upload(req, res);

    console.log(req.file);
    if (req.file == undefined) {
      return res.send(`You must select a file.`);
    }

    return res.send(`File has been uploaded.`);
  } catch (error) {
    console.log(error);
    return res.send(`Error when trying upload image: ${error}`);
  }
};

module.exports = {
  uploadFile: uploadFile
};

Define routes

In routes folder, define routes in web.js with Express Router.

const express = require("express");
const router = express.Router();
const homeController = require("../controllers/home");
const uploadController = require("../controllers/upload");

let routes = app => {
  router.get("/", homeController.getHome);

  router.post("/upload", uploadController.uploadFile);

  return app.use("/", router);
};

module.exports = routes;

There are 2 routes: – GET: Home page for the upload form. – POST "/upload" to call the upload controller. This is for action="/upload" in the view.

Create Express app server

Finally, we create an Express server.

server.js

const express = require("express");
const app = express();
const initRoutes = require("./routes/web");

app.use(express.urlencoded({ extended: true }));
initRoutes(app);

let port = 3000;
app.listen(port, () => {
  console.log(`Running at localhost:${port}`);
});

Run & Check result

On the project root folder, run this command: node src/server.js

The console shows:

Running at localhost:3000

Open browser with url http://localhost:3000/.

Click on Submit button, if the file is uploaded and stored in MongoDB successfully, the browser will show:

The console shows image’s information:

{ fieldname: 'file',
  originalname: 'extreme.jpg',
  encoding: '7bit',
  mimetype: 'image/jpeg',
  id: 5dd60e6aee27a520ccad86a0,
  filename: '1574309482432-bezkoder-extreme.jpg',
  metadata: null,
  bucketName: 'photos',
  chunkSize: 261120,
  size: 89431,
  md5: '0d072efbb134b3b186c5da705e0e7059',       
  uploadDate: 2019-11-21T04:11:23.264Z,
  contentType: 'image/jpeg' }

Check MongoDB database, you will see bezkoder_files_db with 2 collections: photos.chunks & photo.files:

Node.js upload/store multiple images in MongoDB

Now I will show you how to modify some code to deal with multiple images instead of only one image at a time.

Change form for uploading multiple images

For the form, we write the input tag with new name & multiple attribute like this.

views/index.html

<input
  type="file"
  name="multi-files"
  multiple
  id="input-files"
  class="form-control-file border"
/>

Modify middleware for uploading & storing image

middleware/upload.js

...

// var uploadFile = multer({ storage: storage }).single("file");
var uploadFiles = multer({ storage: storage }).array("multi-files", 10);
var uploadFilesMiddleware = util.promisify(uploadFiles);
module.exports = uploadFilesMiddleware;

array() function limits the number of files to upload each time, the first parameter is the name of input tag (in html view: <input type="file" name="multi-files">), the second parameter is the max number of files (10).

Controller for uploading multiple images

With the controller, we export a new function: uploadFiles.

controllers/upload.js

const upload = require("../middleware/upload");

const uploadFiles = async (req, res) => {
  try {
    await upload(req, res);
    console.log(req.files);

    if (req.files.length <= 0) {
      return res.send(`You must select at least 1 file.`);
    }

    return res.send(`Files have been uploaded.`);
  } catch (error) {
    console.log(error);

    if (error.code === "LIMIT_UNEXPECTED_FILE") {
      return res.send("Too many files to upload.");
    }
    return res.send(`Error when trying upload many files: ${error}`);
  }
};

module.exports = {
  uploadFiles: uploadFiles
};

There is a additional part in the catch() block. We check if the error.code is "LIMIT_UNEXPECTED_FILE" for showing user the message when he tries to upload more than 10 images/files.

Don't forget to change the controller method on router:

router.post("/upload", uploadController.uploadFiles);

Run & Check result

Run the command: node src/server.js

And the console shows:

Running at localhost:3000

Open your browser with url http://localhost:3000/, add some images like this:

Click on Submit button. If these images are uploaded and stored in MongoDB successfully, you can see:

The console shows these images' information:

[ { fieldname: 'multi-files',
    originalname: 'circle.png',
    encoding: '7bit',
    mimetype: 'image/png',
    id: 5dd637361ae0143fdc572105,
    filename: '1574319926050-bezkoder-circle.png',  
    metadata: null,
    bucketName: 'photos',
    chunkSize: 261120,
    size: 193593,
    md5: 'f6455d94e5ec26a1b6eb75b334220cbd',        
    uploadDate: 2019-11-21T07:05:30.273Z,
    contentType: 'image/png' },
  { fieldname: 'multi-files',
    originalname: 'JavaDuke.png',
    encoding: '7bit',
    mimetype: 'image/png',
    id: 5dd637361ae0143fdc572106,
    filename: '1574319926110-bezkoder-JavaDuke.png',    metadata: null,
    bucketName: 'photos',
    chunkSize: 261120,
    size: 112767,
    md5: 'b7f0fa8ea1932850d99a64b35484484a',        
    uploadDate: 2019-11-21T07:05:30.275Z,
    contentType: 'image/png' },
  { fieldname: 'multi-files',
    originalname: 'lotus.jpg',
    encoding: '7bit',
    mimetype: 'image/jpeg',
    id: 5dd637361ae0143fdc572107,
    filename: '1574319926121-bezkoder-lotus.jpg',   
    metadata: null,
    bucketName: 'photos',
    chunkSize: 261120,
    size: 375719,
    md5: '26dc2e512d7c021daaa7cb46215d4a5b',        
    uploadDate: 2019-11-21T07:05:32.326Z,
    contentType: 'image/jpeg' } ]

Check MongoDB database: - photos.files collection:

- chunks.files collection:

If you try to upload more than 10 files at a time, you can see the error like this:

options: customizes how to establish the connection, specified in the documentation.

– The function with the parameter is the name of input tag (in html view: <input type="file" name="file">) will store the single file in req.file.

If you want to do more, for example, resize the images, please visit this post:

node-js-upload-store-images-mongodb-demo-single-image
node-js-upload-store-images-mongodb-demo-single-image-successful
node-js-upload-store-images-mongodb-demo-single-image-db-result

For multiple images, we use another function: instead of single().

node-js-upload-store-images-mongodb-demo-multiple-images
node-js-upload-store-images-mongodb-demo-multiple-images-successful
node-js-upload-store-images-mongodb-demo-multiple-images-db-result-1
node-js-upload-store-images-mongodb-demo-multiple-images-db-result-2
node-js-upload-store-images-mongodb-demo-multiple-images-error
MongoClient.connect
single()
Upload & resize multiple images in Node.js using Express, Multer, Sharp
array()