Multer super slow upload after recieving post request with images - node.js

Hello I'm on a (ReactJs Node Mysql Express) stack, my website has an events tab which the admin could upload to it events.
Each event has a cover photo, inner photos, Title, and a brief text.
So I send this whole form in a single post request (is it good?)
var fileUpload = multer({ storage:storage,
limits:{fileSize:150*1024*1024}
})
const multipleUpload = fileUpload.fields([{ name: 'coverPhoto', maxCount: 1 }, { name: 'innerPhotos', maxCount: 30 }])
const storage = multer.diskStorage({
destination: (req, files, cb) => {
cb(null, '../client/build/imgs/events')
},
filename: (req, files, cb) => {
cb(null, files.originalname)
}
})
The server does recieve the request perfectly but after multer receives the photos it takes so long to move them to the fs and the reverse proxy would send a 524 error that it took so long knowing that the format is webp and the photos are so small in size.
Any idea why is it taking so long?
I tried to move to formidable but I couldn't figure how to retrieve multiple input fields with multiple files in it ( I only succeeded in sending one input not multiple inputs)
Thank you

Related

display file name in a single array in multer using nodejs

here is a part of my code of multer using nodejs
const storageEngine = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, './Images')
const Files = [file.originalname]
console.log(Files)
},
filename: (req, file, cb) => {
cb(null, file.originalname)
}
})
the console log of the above code is this:
['image.png']
['image2.png']
['image3.png]
so i want all file names to be in one array to be posted in mysql in one go as i do not want to send multiple request to mysql as there are numerous amount of images.
so all i want is the file names to be present in one single array like this:
['image.png', 'image2.png', 'image3.png']
The destination event that you use is invoked once per uploaded file, so you cannot use it to collect all file names.
Assuming you have an input field <input type="file" multiple name="upload">, you can instead use
app.use(storageEngine.array("upload"))
.use(function(req, res, next) {
console.log(req.files.map(file => file.originalname));
next();
});

Unable to upload Files Using Multer React Js And Express

Attaching Documents Pic
As shown in the pic i am attaching my documents.
onDrop: (acceptedFiles, rejectedFiles) => {
if (rejectedFiles.length) {
toast.error('You can upload images , Words and Excel files !.')
} else {
console.log(acceptedFiles)
setFiles([...files, ...acceptedFiles.map(file => Object.assign(file))])
}
}
axios.post('http://localhost:5000/AddEmployee', {
user, employeeDocuments : user[2].documents
})
.then(res => {
console.log(res)
})
.catch(err => {
console.log(err)
})
I am storing all test documents in the employeedocuments array and then i am sending post request to backend.
employeeDocuments array in console log view
Here i am console log the employeeDocuments array it is looking fine.
enter code here
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "./public/uploads");
},
filename: function (req, file, cb) {
cb(null, file.fieldname + "-" + Date.now() + path.extname(file.originalname));
},
});
var upload = multer({ storage: storage });
var uploadMultiple = upload.fields([{ name: 'employeeDocuments', maxCount: 10 }])
This is my backend multer code to upload files i have used the name employeeDocuments to upload files but multer is not uploading these files.Rather i used postman and it was working fine. But when i upload these files using react by post request these files not get uploaded.
I faced a similar issue and I was able to fix it by modifying my axios post request to sending Form Data:
const formData = new FormData()
formData.append('imagePath', image)
The have the upload in the post like this: router.post("/AddEmployee",upload, async (req, res)
And store it in the DB as a path using req.file.path
Sorry if its a bit confusing but this is everything I have in my code and its fully working

Save image url to database after upload

I upload an image from a react native expo app.
In the back end, I have this code :
const storage = multer.diskStorage({
destination: (req, file, callback) => {
callback(null, "avatars");
},
filename: (req, file, callback) => {
let imagePath = Date.now() + path.extname(file.originalname);
callback(null, imagePath);
},
});
const upload = multer({ storage: storage });
app.use("/uploadAvatar", upload.single("avatar"), (req, res) => {
res.status(200).json("Image enregistrée !");
});
It works fine and save the image into a folder.
What I need to do, is to save the image path in the database.
The image is an avatar for a user profile, so I need to add its path to the user table.
Suppose you are storing the image in your middleware:
app.use('/uploadAvatar', upload.single('avatar'), async (req, res) => {
// Assume that you're storing the image with a function,
// in this case you just need to pass the filename into
// your function. This is a pseudocode and is not expected to work
// as it is, so please adjust accordingly.
const result = await storeImage(req.file.filename);
// Return the response as JSON.
res.status(200).json('Image enregistrée!');
});
Basically, you have to inspect the req.file that would be populated after you call the upload.single('avatar') middleware. In this case, we're taking the filename to be stored into the database. You can do any path/file/property manipulations that you might want to do before storing that image, though.
For further information about req.file and what properties it contains, please see the Multer documentation.

Heroku images are gone in new pushes

Need your Help!
I deployed my nodejs app (only backend) to heroku and it includes a part where the user must insert documents in format jpg, jpeg, png! All pictures are located in the static folder (/assets/docs)! before pushing the changed code, I tried to create users and their pictures are shown! but when I do a new push to heroku, old files are gone and not showing!
I tried to ignore that static folder in new pushes - /assets/docs/* useless, /assets - useless, /assets/docs - useless
But as an experiment, I put 1 .jpg file in that static folder and pushed it. it always stays even in new pushes (with ignores also)
Using multer and mongoose
file uploading with multer
const multer = require('multer')
const path = require('path')
const storage = multer.diskStorage({
destination: 'assets/docs/',
filename: function(req, file, cb) {
cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname))
}
})
const up = multer({
storage: storage,
limits: {
fileSize: 5 * 1024 * 1024
},
fileFilter(req, file, cb) {
if (!file.originalname.match(/\.(png|jpg|jpeg|docx|doc|pdf)$/)) {
return cb (Error("Allowed file types are png jpg jpeg docx doc pdf"), false)
}
cb (null, true)
}
})
saving files - mongoose
router.post('/register-employee', uploadDocument.single('passport'), async (req, res) => {
try {
const emp = await new Employee({
...req.body,
passport: `docs/${req.file.filename}`
})
await emp.save()
res.json(emp)
} catch (e) {
res.status(500).json({errorMessage: e.message})
}
})
gitignore file
/node_modules
/.vscode
/.idea
/config
/assets/docs
setting up a public folder
const publicDir = path.join(__dirname, '../assets')
app.use(express.static(publicDir))
The Heroku filesystem is ephemeral - that means that any changes to the filesystem whilst the dyno is running only last until that dyno is shut down or restarted.
Each dyno boots with a clean copy of the filesystem from the most recent deploy. This is similar to how many container based systems, such as Docker, operate.
You can get over this issue by using an external file storage system like Amazon s3 to persist data across restarts on a dyno.
You can read more here: https://help.heroku.com/K1PPS2WM/why-are-my-file-uploads-missing-deleted

Send Blob File from html form to express server so it can be uploaded to cloud

So I'm trying to make the html form:
<form action="blahblah" encblah="multipart/form-data" whatever>
Thats not the problem, I need to make that form send the blob to express
app.post('/upload/avatars', async (req, res) => {
const body = req.body;
console.log(req.file);
console.log(body);
res.send(body);
});
So I can access the blob, create a read stream, pipe it to the cloud, and bam, upload the file without downloading anything on the express server it self.
Is that possible?
If yes, please tell me how.
If no, please tell me other alternatives.
On the client we do a basic multi-part form upload. This example is setup for a single image but you could call uploadFile in sequence for each image.
//client.ts
const uploadFile = (file: File | Blob) => {
const formData = new FormData();
formData.append("image", file);
return fetch("/upload", {
method: "post",
body: formData,
});
};
const handleUpload = (event: any) => {
return event.target.files.length ? uploadFile(event.target.files[0]) : null;
};
On the server we can use multer to read the file without persisting it to disk.
//server.js
const express = require("express");
const app = express();
const multer = require("multer");
const upload = multer();
app.post(
"/upload",
upload.fields([{ name: "image", maxCount: 1 }]),
(req, res, next) => {
console.log("/upload", req.files);
if (req.files.image.length) {
const image = req.files.image[0]; // { buffer, originalname, size, ...}
// Pipe the image.buffer where you want.
res.send({ success: true, count: req.files.image.originalname });
} else {
res.send({ success: false, message: "No files sent." });
}
}
);
For larger uploads I recommend socket.io, but this method works for reasonably sized images.
it is possible, but when you have a lot of traffic it would overwhelm your express server (in case you are uploading videos or big files ) but if it's for uploading small images (profile image, etc...) you're fine. either way you can use Multer npm
I'd recommend using client-side uploading on ex: s3-bucket, etc..., which returned a link, and therefore using that link.

Resources