Home » NodeJS » Multer: File Uploading ULTIMATE GUIDE

Multer: File Uploading ULTIMATE GUIDE

Multer File Uploading ULTIMATE GUIDE

Multer is a middleware.

Multer is a body parsing middleware that handles content type multipart/form-data.

Multer for uploading Single Image

If you want to upload a single image at a time, then follow these steps:

Prerequesites

Make sure you have a running Basic Express App.

Install

npm install multer

import the multer into our server.js file

const multer = require("multer")

Let’s Add destination folder & file name

In this, we will set file’s name, destination, add validation regarding the type of the file.

ADD DESTINATION FOLDER

METHOD 1:

If you use this method, you have to create a folder.

Create ‘uploads’ folder — here we will store the uploaded files.

// server.js

const storage = multer.diskStorage({

  destination: (req, file, cb) => {
    cb(null, "uploads/")  // destination folder
  }

})

METHOD 2:

With this method, you don’t have to create “uploads” folder, it will automatically create that folder for you.

// server.js

const fs = require('fs');

const storage = multer.diskStorage({

  destination: (req, file, cb) => {
    const dir = 'uploads/';
    if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
    cb(null, dir);
  },
  
});

Note: We need a package called “fs” so that we could have control over directory and check whether “uploads” folder exists or not — and finally create the”uploads” folder. We don’t need to install fs module because it’s built-in core module, so we can use it without any installation.

This line “if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });” checks whether the directory exists or not, if it doesn’t exist, it will create that folder.

This line “cb(null, dir);” sets the destination folder for the file given in dir variable.

ADD FILE NAME

This file name can be applicable for all files including photos, pdf documents, and videos.

Note: Because we are using path (e.g: path.extname), so we need to import that package too. You don’t need to install the path module in Node.js because it is a built-in module. You can use it directly without any installation.

const path = require('path');

Original Name + Timestamp

filename: (req, file, cb) => {
  cb(null, file.originalname.split('.')[0] + '-' + Date.now() + path.extname(file.originalname)); 
}

Output: ImageName-1727337530899.jpg

Format: [originalNameWithoutExtension]-[timestamp][originalExtension]

file.originalname.split('.')[0] - Original Name of File without extension

Date.now() - Get current timestamp in milliseconds from epoch era

path.extname(file.originalname) - Get file extension

Original Name + Date + Time

filename: (req, file, cb) => {
  const originalName = file.originalname.split('.')[0]; // Extract name without extension
  const date = new Date();
  const formattedDate = date.toISOString().split('T')[0]; // Format: YYYY-MM-DD
  const formattedTime = date.toTimeString().split(' ')[0].replace(/:/g, '-'); // Format: HH-MM-SS

  const newFilename = `${originalName}-${formattedDate}-${formattedTime}${path.extname(file.originalname)}`;
  cb(null, newFilename);
}

Output: ImageName-2024-10-17-13-45-23.jpg

ALL PIECES TOGETHER

I have used Method 2 of Destination Folder and 2nd Option for File Name.

const multer = require('multer');
const fs = require('fs'); // // Don't forget to require 'fs'
const path = require('path'); // Don't forget to require 'path'

const storage = multer.diskStorage({

  destination: (req, file, cb) => {
    const dir = 'uploads/';
    
    if (!fs.existsSync(dir)) {
      fs.mkdirSync(dir, { recursive: true });
    }
    
    cb(null, dir);
  },
  
  
  filename: (req, file, cb) => {
    const originalName = file.originalname.split('.')[0]; // Extract name without extension
    const date = new Date();
    const formattedDate = date.toISOString().split('T')[0]; // Format: YYYY-MM-DD
    const formattedTime = date.toTimeString().split(' ')[0].replace(/:/g, '-'); // Format: HH-MM-SS

    const newFilename = `${originalName}-${formattedDate}-${formattedTime}${path.extname(file.originalname)}`;
    cb(null, newFilename);
  },
  
  
});


var upload = multer({ storage: storage }); // Initialize multer with the storage configuration

module.exports = upload; // Export upload middleware for use in your routes

Note: We don’t need to install fs and path modules because they are built-in core modules, so we can use them without any installation.

Output: Your files will be stored in uploads folder with file name structure [ Original Name + Date + Time ]

Creating an upload route (i.e. POST Route)

Storing SINGLE

// Single file (receives only a single file)
app.post("/upload", upload.single("file"), (req, res) => {
  console.log(req.file)
  return res.send("Single file")
})

// POST route to handle image upload and form submission
app.post('/upload', upload.single('image'), (req, res) => {
  const imagePath = req.file ? req.file.path : null; // Path to the uploaded file
  const { cardTitle, brand } = req.body;

  // SQL query to insert form data and image path into MySQL
  const query = `
    INSERT INTO my_db (cardTitle, brand, displayImage, imageAddress)
    VALUES (?, ?, ?, ?)
  `;

  db.query(query, [cardTitle, brand, imagePath, req.file.filename], (err, result) => {
    if (err) {
      console.error('Error inserting data:', err);
      return res.status(500).json({ message: 'Error inserting data' });
    }

    res.json({ message: 'Product added successfully!' });
  });
});

Storing MULTIPLE

//Multiple files ( receives several files, but we can set the maximum limit files [for ex: 10 max limit] )

app.post("/upload", upload.array("file", 10), (req, res) => {
  console.log(req.files)
  return res.send("Multiple files")
})

// POST route to handle image upload and save the image paths and inputs to MySQL
app.post('/upload', upload.array('images', 11), (req, res) => {
  const files = req.files;

  // Prepare an object to hold image paths for each specified column
  const imageData = {
    displayImage: files[0] ? files[0].path : null,
    firstImage: files[1] ? files[1].path : null,
    secondImage: files[2] ? files[2].path : null,
    thirdImage: files[3] ? files[3].path : null,
    fourthImage: files[4] ? files[4].path : null,
    fifthImage: files[5] ? files[5].path : null,
    sixthImage: files[6] ? files[6].path : null,
    seventhImage: files[7] ? files[7].path : null,
    eighthImage: files[8] ? files[8].path : null,
    ninthImage: files[9] ? files[9].path : null,
    tenthImage: files[10] ? files[10].path : null,
  };

  // Extract additional input fields from the request body
  const {
    slug,
    cardTitle,
    category,
    brand,
    soldNumber,
    actualPrice,
    markedPrice,
    rating,
    freeShipping,
    stockStatus,
    title,
    description,
    bigDescription,
    specification
  } = req.body;

  // SQL query to insert image paths and other input fields into the database
  const query = `
    INSERT INTO my_db (
      displayImage, firstImage, secondImage, thirdImage, fourthImage,
      fifthImage, sixthImage, seventhImage, eighthImage, ninthImage,
      tenthImage, slug, cardTitle, category, brand, soldNumber,
      actualPrice, markedPrice, rating, freeShipping, stockStatus,
      title, description, bigDescription, specification
    ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
  `;

  // Execute the query with the values from imageData and input fields
  db.query(query, [
    imageData.displayImage, imageData.firstImage, imageData.secondImage,
    imageData.thirdImage, imageData.fourthImage, imageData.fifthImage,
    imageData.sixthImage, imageData.seventhImage, imageData.eighthImage,
    imageData.ninthImage, imageData.tenthImage,
    slug, cardTitle, category, brand, soldNumber,
    actualPrice, markedPrice, rating, freeShipping, stockStatus,
    title, description, bigDescription, specification
  ], (err, result) => {
    if (err) {
      console.error('Error saving data to database:', err);
      return res.status(500).json({ message: 'Error saving data to database' });
    }

    // Send success response
    res.json({ message: 'Images and data uploaded and saved successfully!', imageData });
  });
});

FINSIHED !!!

Creating a Frontend for File Upload

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>File Upload</title>
</head>
<body>
  <h1>File Upload Example</h1>
  <form action="/upload" method="POST" enctype="multipart/form-data">
    <input type="file" name="file">
    <button type="submit">Upload File</button>
  </form>
</body>
</html>

form fields upload

image upload

video upload

pdf upload

folder upload

Final Code