Multer array returns only one file - node.js

I'm using multer to store multiple files in the database.
The files are stored properly in my DB, however, if I print req.files I only get just one file.
This is my code:
var storage = GridfsStorage({
url: config.mongo.uri,
filename(req, file, cb) {
cb(null, file.originalname);
},
metadata(req, file, cb) {
cb(null, {owner: req.params.driver})
}
});
var upload = multer({ storage: storage }).array('files[]');
return upload(req, res, function (err) {
if(err) {
handleError(err);
}
console.log(req.files); // --> Getting only one file, even thought it stores all of them
respondWithResult(req.files, 201);
})
Thanks for helping!

Related

Not able to save image with original name and extension through multer in node.js

Hi I am trying to save an image in my image folder through multer but the issue is that the file is being saved with a randomly generated filename without extension.I have tried to resolve this issue by referring to various articles but still facing the same issue.
referred the following :
Multer is not saving the file as the same name and without extension?
The file gets saved in the image folder like below :
a9bfcba8e950ccfbdaf7f0d2f8d58374
Hence if someone could please help me resolve this issue.
profile.js
const upload = multer({
dest:'images',
filename: function (req, file, cb) {
cb(null, file.originalname)
},
limits: {
fileSize: 10000000,
},
fileFilter(req, file, cb) {
if(!file.originalname.match(/\.(jpg|jpeg|png|JPG|HEIC)$/)) {
return cb(new Error('Please attach an image'))
}
cb(undefined, true);
}
})
router.post('/user/upload', upload.single('profile_pic') , async (req,res) => {
console.log(req.body)
const url = req.protocol + '://' + req.get('host')
//when inserting the file in the database we are able to send the exact location with original file name and extension.
var filepath = url + '/Users/images/';
var reqFiles = (filepath + req.file.filename + path.extname(req.file.originalname)
console.log(req.file);
const notify = new user({
userId: req.body.userId,
profile_pic: reqFiles
})
you need to do step wise process for storing a file.
//storage for image upload
const storage = multer.diskStorage({
destination: './upload',
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname));
}
});
//file filter for extention
let fileFilter = function (req, file, cb) {
console.log(file.mimetype)
const allowedMimes = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif'];
if (allowedMimes.includes(file.mimetype)) {
cb(null, true);
} else {
cb(null, false);
}
};
//upload for to pass storage, file size limit and filter
//maximum file size is 10Mb
const upload = multer({
storage: storage,
limits: { fileSize: 10 ** 7 },
fileFilter: fileFilter
}).single('userImage');
then call your route.
router.post('/upload', (req,res)=>{
upload(req, res, (err)=>{
if(err){
console.log(err)
}
else{
console.log(req.file)
console.log(req.file.path)
}
})
})
By following this approach then definitely your error will solved.

How to make sure that the given file to multer exists in Node.JS

First of all I'm working with Node.JS with Express
I made a code that allows me to upload an image with multer to a specific directory, and here is a simplified version of it:
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'images')
},
filename: (req, file, cb) => {
cb(null, "some_random_name.jpg")
},
})
const upload = multer({
storage: storage,
fileFilter: (req, file, cb) => {
if (path.extname(file.originalname) != '.jpg')
return cb("Invalid file type, try uploading a '.jpg' file")
else
cb(null, true)
}
}).single('image')
router.post('/', (req, res) => {
upload(req, res, (err) => {
if (err)
return res.status(400).send({ error: err.message })
else
dbController.query(/* INSERT INTO images ... */)
}
)
})
The code works perfectly, but when I give a non existing file to it, it creates a file as if the file existed.
So to solve this I have to make sure that the file really exists before uploading it.
How can I implement this.

How to import an Excel File with Nodejs?

I am a nodeJS programmer. I want to the import excel file into my mongoDB database table with validation.
Validation like if any field is blank then that record not inserted into database and after importing all data from the file display this record not inserted because that field is blank.
There are many package are available but i am confuse which one is better for import excel file.
So please help me which package to use to import an Excel file. And if a demo code is possible please answer it.
router.post('/transferFiles', function (req, res) {
var neatCsv = require('neat-csv');
var array;
var fs = require('fs');
var storage02 = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './uploads/');
},
filename: function (req, file, cb) {
cb(null, Date.now() + file.originalname);
}
});
var upload02 = multer({
storage: storage02
}).single('file');
console.log("req.file");
console.log(req.files);
upload02(req, res, function (err) {
if (err) {
console.log("upload error 1" + err);
}
//console.log(req.file);
/** Multer gives us file info in req.file object */
if (!req.file) {
console.log('No file Passed 1');
return;
}
fs.readFile(req.file.path, async function (err, result02) {
if (err) {
console.error(err);
return;
}
array = await neatCsv(result02);
});
here result02 is added in array.so easily you can data to mongodb with help of json

multer: dynamic destination path

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({});
});
});
Here's code for dynamic path by argument!
exports.upload = (folderName) => {
return imageUpload = multer({
storage: multer.diskStorage({
destination: function (req, file, cb) {
const path = `src/assets/uploads/${folderName}/`;
fs.mkdirSync(path, { recursive: true })
cb(null, path);
},
// By default, multer removes file extensions so let's add them back
filename: function (req, file, cb) {
cb(null, Date.now() + path.extname(file.originalname));
}
}),
limits: { fileSize: 10000000 },
fileFilter: function (req, file, cb) {
if (!file.originalname.match(/\.(jpg|JPG|webp|jpeg|JPEG|png|PNG|gif|GIF|jfif|JFIF)$/)) {
req.fileValidationError = 'Only image files are allowed!';
return cb(null, false);
}
cb(null, true);
}
})
}
and call it
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}`)
}
})
})
In my project I use multer as follow:
1.Store the file first in a common directory, like /tmp/.
2.Copy/move the file anywhere you want, to CDN in my case, and to a user folder in yours.
3.Remove the original file in /tmp if needed.
And maybe let upload = multer({
storage: storage,
dest: 'documents/'
}); you should remove the dest here since you specified dest in storage, right?
const storage = multer.diskStorage({
destination: function(req, file, callback){
callback(null, path.dirname('D:/') + 'Integra Qamba Site/');
},
filename: function(req, file, callback){
let data = new Date();
callback(null, dateTime +".jpg");
}
});

node.js multer rename uploaded file

I am trying to rename an image file uploaded with multer by the request parameters.
Here is my code:
router.route('/upload/:userid')
.post(multer({
dest: 'uploads/'
}), function(req,res){
fs.readFile('uploads/' + req.files.file.name, function(err, data) {
fs.writeFile('uploads/' + req.params.userid + '.' + req.files.file.extension, data, function(err) {
fs.unlink('uploads/' + req.files.file.name, function(){
if(err) throw err;
});
});
});
res.json({ message: 'Successfully uploaded image!' });
});
It works great but I was wondering if it exists something cleaner and easier with multer rename function.
It already tried something like this:
router.route('/upload/:userid')
.post(multer({
dest: 'uploads/',
rename: function(req,res) {
return req.params.userid
}
}), function(req,res){
res.json({ message: 'Successfully uploaded image!' });
});
But it does not work because req is not populated yet (undefined).
I use httpie to test my code with the following command:
http.exe -f POST http://localhost:8080/upload/171284 file#D:\....\cat.jpg
Is it possible to use rename function of multer to do what I do with fs?
Or is there a better way?
Thank you for your feedbacks.
Thomas
EDIT
My new code using diskStorage:
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads/')
},
filename: function (req, file, cb) {
cb(null, req.params.userid + '-')
}
})
var upload = multer({ storage: storage })
router.route('/upload/:userid')
.post(multer({
storage: storage
}), function(req,res){
res.json({ message: 'Successfully uploaded image!' });
});
That throws an error:
Error: Route.post() requires callback functions but got a [object Object]
Ther is no rename in Multer constructor, insted of that, there is a filename in DiskStorage.
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, '/tmp/my-uploads')
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
})
var upload = multer({ storage: storage })
filename is used to determine what the file should be named inside
the folder. If no filename is given, each file will be given a
random name that doesn't include any file extension.

Resources