I am writing a node application and I was looking for something to upload files on the server. I could get files to upload when there was only one static directory. But I need to make directories per user and then upload files to those, according to the user that's logged in. I looked stuff up but everything that I try ends in an Error: ENOENT: no such file or directory, open ... error. What I am trying to do currently is this -
let storage = multer.diskStorage({
destination: function(req, file, cb) {
let dest = path.join(__dirname, './documents', 'somenameigetfromtheuser');
let stat = null;
try {
stat = fs.statSync(dest);
}
catch (err) {
fs.mkdirSync(dest);
}
if (stat && !stat.isDirectory()) {
throw new Error('Directory cannot be created');
}
cb(null, dest);
}
});
let upload = multer({
storage: storage,
dest: 'documents/'
});
app.post('/testUpload', upload.single('testfile'), (req, res) => {
res.json({
test: 'test'
})
});
There is a similar question that has been answered but it doesn't work that way for me because I want the directory name from the request object.
When I remove the storage property in my multer initialization, the files are stored in the documents directory with a random name. I want the file to have its original name and I want it to be stored in a directory where I get the name of the directory from the req object.
Help a brother out, thanks!
edited
See https://github.com/expressjs/multer#diskstorage
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.
Due to that, first write file in temp directory, read directory name from req and move file:
fs = require('fs-extra'); //npm install fs.extra
...
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, '../tempDir/')
},
filename: function (req, file, cb) {
cb(null, file.originalname)
}
});
var upload = multer({
storage: storage
}).single('file');
upload(req, res, function (err) {
if (err) {
res.json({});
return;
}
var dir = JSON.parse(req.body.data).directory;
var filename = req.file.filename;
fs.move('../tempDir/' + fileName, '../tempDir/' + dir + '/' + fileName, function (err) {
if (err) {
return console.error(err);
}
res.json({});
});
});
Make sure you append first the textfields on the client-side and only then do you append the files. In my case i had something like this:
`
for(let i=0; i<files.length;i++)
{
formData.append("files[]",files[i]);
}
formData.append("username",username);
`
The fix was to first append the textfield like so:
`
formData.append("username",username);
for(let i=0; i<files.length;i++)
{
formData.append("files[]",files[i]);
}
`
Here's what I do for uploading files to dynamic directories.
In frontend I use URL parameters to pass user IDs.
await axios({
method: 'post',
data: formData,
url: '/api/upload?userId=123',
headers: { 'content-type': 'multipart/form-data' }
})
In backend get that parameter and use for destination. Also create the directory if it doesn't exist.
const upload = multer({
storage: multer.diskStorage({
destination: (req, file, cb) => {
const directory = `./public/uploads/${req.query.userId}`
if (!fs.existsSync(directory)) {
fs.mkdirSync(directory, { recursive: true })
}
cb(null, directory)
},
filename: (req, file, cb) => {
cb(null, `${Date.now()}-${file.originalname}`)
}
})
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With