Preface: using Node.js w/Express to build a blog website and using multer to upload an image to mongoDB.
I have a problem with image data not saving to MongoDB.
When I use enctype="multipart/form-data in my HTML form, I get the following in my terminal
fieldname: 'myImage',
originalname: 'photo_2021-12-27_20-07-58.jpg',
encoding: '7bit',
mimetype: 'image/jpeg',
destination: './uploads/',
filename: 'photo_2021-12-27_20-07-58.jpg',
path: 'uploads\\photo_2021-12-27_20-07-58.jpg',
size: 134172
}
Which is correct, the image also uploads into a separate uploads folder which is also correct, however the image data doesn't save to my mongoDB.
However, when I remove enctype="multipart/form-data", I don't have the file data in my terminal, nor does the image upload to the separate folder. However I DO! get the image data in my mongoDB. This is such a weird problem. Can anyone help?
Also, sorry for the amount of code I have just unleashed. If anyone actually takes the time to answer this then thank you!
Routes
const express = require('express');
const router = express.Router();
const blogController = require('../controllers/blogController')
const multer = require('multer');
const storage = multer.diskStorage({
//destination for files
destination: function (request, file, callback) {
callback(null, './uploads/');
},
//add back the extension
filename: function (request, file, callback) {
callback(null, file.originalname);
},
});
const upload = multer({
storage: storage,
});
router.get('/create', blogController.blog_create_get);
router.get('/', blogController.blog_home);
router.post('/', upload.single('myImage') ,blogController.blog_create_post);
router.get('/:id', blogController.blog_details);
router.delete('/:id', blogController.blog_delete_post);
module.exports = router
Controller code
const blog_create_post = (req, res) => {
console.log(req.file);
const blog = new Blog(req.body, {
})
blog.save()
.then(() => {
res.redirect('/blogs')
})
.catch((err) => {
console.log(err);
})
}
Schema
image: {
data: Buffer,
contentType: String
},
const Blog = mongoose.model('Blog', blogSchema)
module.exports = Blog;
Midleware
// Static Files | Middleware
app.use(express.static('Public'));
app.use(express.urlencoded({ extended: true }));
app.use(morgan('dev'))
app.use('/uploads',express.static('uploads'))
HTML form
<form action="/blogs" enctype="multipart/form-data" method="POST">
<label for="image">Select image:</label>
<input type="file" id="image" name="myImage" accept="image/*">
<input type="submit" value = "Upload Photo">
Multer is triggered only when the enctype of your form is enctype="multipart/form-data". Example from their doc:
<form action="/profile" method="post" enctype="multipart/form-data">
<input type="file" name="avatar" />
</form>
When you don't provide this enctype your req object contains form data in text, and then it is saved to your database, of course.
In order to save binary data to MongoDB you need to open a file designated by
filename: 'photo_2021-12-27_20-07-58.jpg',
path: 'uploads\\photo_2021-12-27_20-07-58.jpg',
and save it appropriately (as text or binary depending on the format and reqs) to the mongodb. To read file check this answer
Related
I am not able to upload two images from two different input tags using Multer.
This is the code of the html form
<form action="/upload" method="post" enctype="multipart/form-data">
<h1>Upload Image 1</h1>
<input name="photo1" type="file" />
<img id="output_image" />
<h1>Upload Image 2</h1>
<input name="photo2" type="file" />
<img id="output_image1" />
<button type="submit">Upload</button>
</form>
This is the code of the nodejs file
const upload = multer({ dest: 'uploads/' })
app.post('/upload', upload.fields([
{ name: 'photo1', maxCount: 1},
{ name: 'photo2', maxCount: 1}
]), (req, res, next) => {
console.log(req.file);
next();
});
But the request object is always undefined.
I tried following the documentation but it didn't solve this issue.
Previously I tried uploading a single file which did work out. For that I removed the below part of the form
<h1>Upload Image 2</h1>
<input name="photo2" type="file" />
<img id="output_image1" />
And this was the nodejs file same as the one on the documentation
const upload = multer({ dest: 'uploads/' })
app.post('/upload', upload.single('photo1'), (req, res, next) => {
console.log(req.file);
next();
});
I am not able to find the mistake here. Is it not possible to take two images from different input fields using multer? Any suggestions would be appreciated.
Use any of the following approaches
Will this help you .any()
Accepts all files that comes over the wire. An array of files will be stored in req.files.
WARNING: Make sure that you always handle the files that a user uploads. Never add multer as a global middleware since a malicious user could upload files to a route that you didn't anticipate. Only use this function on routes where you are handling the uploaded files.
i am saying this from [here][1].
or for multiple files use this
Instead of upload.single('image') you want to do upload.array('image'), and then look at req.files instead of req.file.
3)
app.post("/upload", function(req, res, fields) {
const storage = multer.diskStorage({
destination: "public/data/",
filename: function(req, file, cb){
crypto.randomBytes(20, (err, buf) => {
cb(null, buf.toString("hex") + path.extname(file.originalname))
})
}
});
const upload = multer({
storage: storage
}).fields([{name: "pp"}, {name: "banner"}]);
upload(req, res, (err) => {
if (err) throw err;
});
});
for more explanation https://codingstatus.com/upload-multiple-files-using-multer-in-node-js-and-express/
I wanted to upload images using nodeJS and multer, so I did the following:
Below is my multer configuration:
var multer = require('multer');
var storage = multer.diskStorage({
//Setting up destination and filename for uploads
destination: function (req, file, cb) {
cb(null, 'uploads/');
},
filename: function (req, file, cb) {
cb(null, Date.now() + file.originalname);
}
});
var upload = multer({
storage: storage,
limits:{
fieldSize: 1024*1024*6,
}
});
Below is my route to upload image:
router.post('/designer', upload.single('designerImage'), async (req, res) => {
console.log(req.file);
//rest of the code which is not needed for my query
})
It works perfectly fine when I POST the file using form-data key of type file using POSTMAN. But when I try to send it using a HTML form input, req.file comes out to be undefined and no file gets uploaded to the uploads folder. Below is my HTML form code:
<form action="/designer" method="POST">
<input type="file" name="designerImage">
<form>
What is the solution to this problem? I've spend hours but couldn't get to a solution.
multer only parses multipart/form-data requests, so you need to add enctype="multipart/form-data" to your form
<form action="/designer" method="POST" enctype="multipart/form-data">
<input type="file" name="designerImage">
<form>
I am using Multer to save files I upload through a form but I do not know why my code saves it as a weird name and without extension and I have just used the code from the documentation.
server.js:
const multer = require('multer');
const app = express();
var upload = multer({ dest: 'uploads/' })
app.post('/file', upload.single('filesToAttach'), function (req, res, next) {
console.log(req.file);
loadUserPage(req, res);
})
userPage.ejs:
<form action="/file" method="post" enctype="multipart/form-data">
<div id="frm-attachments">
<div>
<h3>Attachments</h3>
<div>
<input type="file" id="attachFiles" name="filesToAttach" />
<input type="submit" value="Attach">
</div>
<div id="frm-attach-files">
Attached files
<div>
<textarea id="field-attached-files" class="large-textbox" name="attached-files" spellcheck="true" rows="10" cols="50" tabindex="4" disabled="true"></textarea>
</div>
</div>
</div>
</div>
</form>
When I click on the submit button, a new file appear in the folder uploads which is supposed to have the same name and same extension as the file I uploaded in the form, but it has this name instead:
And if I try to print out(req.file), I see this:
Why is this happening? I do not even understand why they write the wrong code in the documentation...
You can set it externally,
Try this,
const multer = require('multer');
const app = express();
var storage = multer.diskStorage({
destination: 'uploads/',
filename: function(req, file, callback) {
callback(null, file.originalname);
}
});
var upload = multer({ storage: storage })
app.post('/file', upload.single('filesToAttach'), function (req, res, next) {
console.log(req.file);
loadUserPage(req, res);
})
You should make a unique name to save your file "generate a random string" and concat this this with the mimetype of your file. as you can see mimetype is already present in the req.file ,
function getFileExtension(mimeType){
if ( mimeType=== 'image/png') {
return '.png';
}
else if ( mimeType=== 'image/jpg') {
return '.jpg';
}
else if ( mimeType=== 'image/gif') {
return '.gif';
}
else {
return '.jpeg';
}
}
If you ae working on images this is the a utility function pass req.mimetype to this and concat its return value to your generated name
When I try to upload a file using a post method, the req.file given by multer is returned undefined.
Maybe it's not getting the correct input by name? I'm really in the dark here.
Thank you in advance for your help
//Front-end form
<form action="/dashboard" method="POST" id="newproduct-form" class="row" enctype='multipart/form-data'>
<input type="file" name="productImage" class="form-control-file" id="exampleInputFile">
</form>
//Backend
const mongoose = require('mongoose');
const multer = require('multer');
const path = require('path');
//Set Storage Engine
const storage = multer.diskStorage({
destination: './public/uploads/',
filename: function(req, file, cb){
cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname));
}
});
//Init upload
const upload = multer({
storage: storage
}).single('productImage');
router.post('/dashboard', (req, res) => {
upload(req,res,(err) =>{
if(err) console.log(err);
console.log(req.file);
});
}
I figured it out. I was using jQuery ajax. By doing $(this).ajaxSubmit({ajax content}); instead of $.ajax({ajax content}) I managed to make it work.
I'm trying to pass a file from my Angular app to a node.js server.
When I run the app, I get the following error:
Error: Please choose files
HTML:
<upload name="fileUpload" formControlName="fileUpload" #fileUpload (listChange)="updateList($event)" data-kind="primary"
[imagePreview]="true">
</upload>
Here is my updateList() method:
updateList(list: any) {
this.demolist = Array.apply(this, list);
this.attachmentReady.emit(this.demolist);
}
Node:
const express = require('express')
const app = express()
const bodyParser = require('body-parser')
const multer = require('multer');
let nodemailer = require('nodemailer');
let aws = require('aws-sdk');
const fs = require('fs');
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads')
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname))
}
});
var upload = multer({ storage: storage });
app.post('/postData', upload.array('fileUpload', 12), (req, res, next) => {
console.log(req.body);
res.json(req.body);
const files = req.files
if (!files) {
const error = new Error('Please choose files')
error.httpStatusCode = 400
return next(error)
}
res.send(files);
}
In a different project, multer is working as expected. Below is the HTML from that project:
<form action="/uploadmultiple" enctype="multipart/form-data" method="POST">
Select images: <input type="file" name="myFiles" multiple>
<input type="submit" value="Upload your files" />
</form>
The difference between my working code & the code that isn't working is that I'm able to use a standard input control if the type is file.
But I need to use an upload control now & my code isn't working when I make that one change.
Can someone please tell me how I can use this control to pass the file? Thanks a lot in advance!
After you have installed multer using npm install --save multer
Basic usage example:
var express = require('express')
var multer = require('multer')
var upload = multer({ dest: 'uploads/' })
var app = express()
app.post('/uploadmultiple', upload.single('myFiles'), function (req, res, next) {
// req.file is the `myFiles ` file
// req.body will hold the text fields, if there were any
})
app.post('/uploadmultiple', upload.array('myFiles', 12), function (req, res, next) {
// req.files is array of `photos` files
// req.body will contain the text fields, if there were any
})
For more information you can read documentation here