0

I have an application to sell cars, I want to upload each car images to a separate folder inside this path country/city.

For example:

Let's say there is a car in Berlin, Germany. When adding this car I am saving the images to this folder Germany/Berlin.

Now I don't want to put all the images of the cars in Berlin, Germany inside the same folder, I want to make a separate folder for each car in Berlin, Germany.

My first approach was to count the number of folders inside the base path and then make a new one by adding one to the number.

For example:

Let's say there are 5 folders inside Germany/Berlin which is the base path for our example

The path would now be like this "Germany/Berlin/6". The problem is that it's making a different folder for each image.

For example:

Let's say there are 5 folders inside Germany/Berlin and there are 4 images for the car that is being uploaded.

The first image goes inside Germany/Berlin/6.

The second image goes inside Germany/Berlin/7.

The third image goes inside Germany/Berlin/8.

The fourth image goes inside Germany/Berlin/9.

I think the problem is that the destination function is being executed for each one of the images.

How can I solve this?

Here's My Code:

const multer = require("multer"); const path = require("path"); const fs = require("fs"); const { onlyImagesAreAllowed } = require("./error_codes"); function uploadFiles(filePath) { const storage = multer.diskStorage({ destination: (req, _file, cb) => { const data = req.body; let dirsCount = 1; let dirPath = `images/${filePath}/${data.country}/${data.city}`; const exists = fs.existsSync(dirPath); if (!exists) { fs.mkdirSync(dirPath, { recursive: true }); } if (exists) { dirsCount = fs .readdirSync(dirPath, { withFileTypes: true }) .filter((dirent) => dirent.isDirectory()) .map((dirent) => dirent.name).length + 1; } dirPath += `${dirsCount}`; fs.mkdirSync(dirPath, { recursive: true }); cb(null, dirPath); }, filename: (_req, file, cb) => { const uniqueSuffix = Date.now() + "-" + Math.round(Math.random() * 1e9); cb(null, file.fieldname + "-" + uniqueSuffix); }, }); const fileFilter = (req, file, callback) => { const acceptedTypes = file.mimetype.split("/"); if (acceptedTypes[0] === "image") { callback(null, true); } else { callback(null, false); callback(new Error(onlyImagesAreAllowed)); } }; const limits = { fileSize: 20 * 1024 * 1024, }; return multer({ storage: storage, fileFilter: fileFilter, limits: limits, }); } module.exports = { uploadFiles, }; 

And the usage is like this:

const express = require("express"); const carsController = require("./cars.controller"); const { uploadFiles } = require("../../utils/upload_files"); const router = express.Router(); router.post( "/addCar", uploadFiles("cars").array("carGallery", 12), carController.addCar ); module.exports = router; 

1 Answer 1

1

If req is the same for each image file (which I assume it is), you can add a custom property to it containing the directory. If that property doesn't exist, run your logic to determine the next directory name; if it does exist, reuse it.

Something like this:

 destination: (req, _file, cb) => { // check if we already determine an upload path for this request if (req._upload_path) { return cb(null, req._upload_path); } // no, we didn't, so determine the next upload path const data = req.body; let dirsCount = 1; ... [the rest of your logic] ... fs.mkdirSync(dirPath, { recursive: true }); // store the upload path we just determined req._upload_path = dirPath; cb(null, dirPath); }, 

As an aside: if you don't really need consecutively numbered directories, I would suggest using a unique id (something like a UUID) instead (it'll be much quicker and less prone to race conditions).

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you very much. I don't need them to be consecutive actually so I'll use the UUID approach you suggested, thank you again.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.