I'd like to upload files to different folder based on user id.
My code is:
const multer = require('multer')
const upload = multer({ dest: 'uploads/'})
app.get('/', function (req, res) {
res.send('Image Extraction Server');
})
app.post('/upload', upload.array('photos',100), (req,res) => {
// get the user id from req
// how can I change the dest path?
res.send('{"status":"ok"}')
})
Is this possible? Thanks.
Indeed you can!
Take a look at DiskStorage in the readme: https://github.com/expressjs/multer#diskstorage

pasting the textual version of the same, so that people can copy-paste easily
const multer = require('multer')
const storage = multer.diskStorage({
destination: (req, file, cb) => {
const { userId } = req.body
const dir = ./uploads/${userId}
fs.exists(dir, exist => {
if (!exist) {
return fs.mkdir(dir, error => cb(error, dir))
}
return cb(null, dir)
})
},
filename: (req, file, cb) => {
const { userId } = req.body
cb(null, UserId-${userId}-Image-${Date.now()}.png)
}
})
const upload = multer({ storage })
@gireeshpunathil ouch sorry.. my bad, you're right :)
Quick note: fs.exists is deprecated.
why when i use req.body its undefined but with params its work??
const storage = multer.diskStorage({
destination: (req, file, callback) => {
const flowID = 4;
const { companyID } = req.body
const path = `./uploads/${companyID}/${flowID}`;
fsex.mkdirsSync(path);
callback(null, path);
},
filename: (req, file, cb) => {
crypto.pseudoRandomBytes(8, (err, raw) => {
if (err) return cb(err);
cb(
null,
date + "_" + raw.toString("hex") + "_" + path.extname(file.originalname)
);
});
}
});
my Route:
router.post("/uploadfile", upload, (req, res, next) => {
const file = req.file;
const{ flowID, companyID} = req.body;
console.log(companyID);
if (!file) {
const error = new Error("Please upload a file");
error.httpStatusCode = 400;
return next(error);
} else {
createFileInDB(file.originalname, flowID, file.filename)
.then(() => {
console.log("File Created");
res.json(file);
})
.catch(err => {
res.status(500).send(err);
});
}
});
@BaruchHeroApps There is a solution by passing the companyID in the path api router:
router.post("/uploadfile/:companyID", upload, (req, res, next) => {
const companyID = req.params.companyID;
And you can also get the companyID in the destination by 'req.params.companyID'
destination: (req, file, callback) => {
const flowID = 4;
const companyID = req.params.companyID;
const path = ./uploads/${companyID}/${flowID};
fsex.mkdirsSync(path);
callback(null, path);
},
........
Here is my solution:
destination: (req, file, cb) => {
const dest = "./app/lab/" + req.userId;
fs.access(dest, function (error) {
if (error) {
console.log("Directory does not exist.");
return fs.mkdir(dest, (error) => cb(error, dest));
} else {
console.log("Directory exists.");
return cb(null, dest);
}
});
},
@gireeshpunathil , The req.body is undefined. Below is my code.
const multer = require('multer');
const fs = require('fs');
const storage = multer.diskStorage({
destination: function (req, file, cb) {
var dir = './uploads/'+req.params.username;
try {
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir);
}
}catch(err) {
console.error(err)
}
cb(null, dir);
},
filename: function (req, file, cb) {
var fileArr = file.originalname.split(".");
fileArr.reverse();
var fileExt = fileArr[0];
fileArr.splice(0,1);
fileArr.reverse();
var newFileName = fileArr.join(".") + "_" + Date.now() + "." + fileExt;
newFileName = newFileName.replace(/ /g,"_");
cb(null, newFileName);
}
});
const storageMulter = multer({
storage: storage,
fileFilter: function(req, file, cb) {
cb(null, true);
}
});
var uploadConfig = storageMulter.array('files',6);
exports.uploadFiles = function(req,res){
uploadConfig(req, res, function (err) {
console.log()
if (err) {
console.log(err);
console.log(req.body);
return err;
}else {
res.send({files: files});
}
})
}
Here is my solution:
destination: (req, file, cb) => { const dest = "./app/lab/" + req.userId; fs.access(dest, function (error) { if (error) { console.log("Directory does not exist."); return fs.mkdir(dest, (error) => cb(error, dest)); } else { console.log("Directory exists."); return cb(null, dest); } }); },
creates a corrupted file in my project, I dont know why....
As
fs.existsis deprecated.
Here is my solution:destination: (req, file, cb) => { const dest = "./app/lab/" + req.userId; fs.access(dest, function (error) { if (error) { console.log("Directory does not exist."); return fs.mkdir(dest, (error) => cb(error, dest)); } else { console.log("Directory exists."); return cb(null, dest); } }); },creates a corrupted file in my project, I dont know why....
There might be other reason. I am still using that code.
@rajatmadaan786
Hey, I don't know if you still have this issue, but I had a similar issue. What I found out was that it matters how the fields in req.body are ordered.
In my case, I was trying to allow users to upload images to their own personal folders, i.e. uploads/${userId}. From the front end, I was sending 2 things: userId and image. Since I was sending an image, my content type was multipart/form-data.
When I did:
formData.append('image', image)
formData.append('userId', id)
I wasn't getting access to userId until after calling upload.single('image'), which was the multer middleware function along my /upload route. Apparently, once multer sees the specified field (in my case 'image'), only all the fields until (and including) that field will be accessible to the multer middleware functions. I derived this from the following line in the multer docs on npm:
Note that req.body might not have been fully populated yet. It depends on the order that the client transmits fields and files to the server.
Therefore, I just switched the order of the fields in my formData, making sure 'image' was last, like this:
formData.append('userId', id)
formData.append('image', image)
And I was able to access userId.
Most helpful comment
pasting the textual version of the same, so that people can copy-paste easily