Upload Image and PDF in rest API using node js with mongoose - node.js

I have try to insert some data into mongodb database using node js REST API but I got an error Unexpected field Im new to node please help me. whitePaper is my pdf file If I upload data like title, description and image only it gives the Correct answer with status code 201 but I try to upload all data and pdf but it gives the error
model code:
description: {
type: String,
required: true
},
imgURL: {
type: String,
required: true
},
whitePaperLink: {
type: String,
required: true,
},
app.js file
app.use('/whitePaper', express.static('whitePaper'));
router file
const whitePaperLink = multer.diskStorage({
destination: './whitePaper/',
filename: (req, file, cb) => {
return cb(null, `${file.fieldname}_${Date.now()}${path.extname(file.originalname)}`);
}
});
const whitePaperFilter = (req, file, cb) => {
if (file.mimetype === 'application/pdf') {
cb(null, true)
} else {
cb(null, false)
}
};
const whitePaperUpload = multer({
storage: whitePaperLink,
limits: {
fileSize: 1024 * 1024 * 5
},
fileFilter: whitePaperFilter
});
router.post('/', checkAuth, imageUpload.single('imgURL'), whitePaperUpload.single('whitePaperLink'),
PostController.create_Post)
controller file
exports.create_Post = async (req, res) => {
const post = new Post({
title: req.body.title,
category: req.body.category,
description: req.body.description,
imgURL: req.file.path,
whitePaperLink: req.file.path,
publishDate: req.body.publishDate,
});
try {
const addPost = await post.save()
res.status(201).json({
message: 'Post Added Succesfully.'
})
} catch (error) {
console.log(error);
res.status(500).json({
message: error
})
}
}

If you'll use upload.single for each field it'll give error Unexpected Field.
Multer takes all files at once for execution, and in your case you've 2 different files and it'll take both files to upload.single.
So, instead of upload.single use upload.fields.
In your route.js, do it like this:
const destination = (req, file, cb) => {
switch (file.mimetype) {
case 'image/jpeg':
cb(null, './images/');
break;
case 'image/png':
cb(null, './images/');
break;
case 'application/pdf':
cb(null, './whitePaper/');
break;
default:
cb('invalid file');
break;
}
}
const storage = multer.diskStorage({
destination: destination,
filename: (req, file, cb) => {
return cb(null, `${file.fieldname}_${Date.now()}${path.extname(file.originalname)}`);
}
});
const fileFilter = (req, file, cb) => {
if (file.mimetype === 'image/jpeg' || file.mimetype === 'image/png' || file.mimetype === 'application/pdf') {
cb(null, true)
} else {
cb(null, false)
}
};
const upload = multer({
storage: storage,
limits: {
fileSize: 1024 * 1024 * 5,
},
fileFilter: fileFilter
});
// add post
router.post('/', upload.fields([{ name: 'imgURL', maxCount: 1 }, { name: 'whitePaperLink', maxCount: 1 }]), PostController.create_Post)
Edit:
You can also do it like this:
const uploadPostData = (req, res, next) => {
upload.fields([{ name: 'imgURL', maxCount: 1 }, { name: 'whitePaperLink', maxCount: 1 }])(req, res, (err) => {
console.log(req.files);
req.body.imgURL = req.files.imgURL[0].path.replace('/\\/g','/');
req.body.whitePaperLink = req.files.whitePaperLink[0].path.replace('/\\/g','/');
next()
})
}
// add post
router.post('/', uploadPostData, PostController.create_Post)

Related

Uploading large video file with nodejs, multer and cloudinary

My code works very well for small videos up to 50MB however when videos weight more than 50MB, it uploads the video but I dont get any cloudinary url hence the video is not loading in my frontend part . I am using nodejs and multer in my backend with cloudinary as storage and react as my frontend.
Any suggestion ?
Cloudinary config
require("dotenv").config();
const cloudinary = require("cloudinary");
cloudinary.config({
cloud_name: process.env.CLOUD_NAME ,
api_key: process.env.API_KEY ,
api_secret: process.env.API_SECRET ,
});
exports.uploads = (file) => {
return new Promise((resolve) => {
cloudinary.uploader.upload(
file,
(result) => {
resolve({ url: result.url, id: result.public_id });
},
{ resource_type: "auto" }
);
});
};
Video controller
const Video = require("../models/videoModel"),
cloud = require("../config/cloudinaryConfig");
module.exports = {
// Create action for a new video
create: (req, res, next) => {
// First check if the file exists in the Database
let test = {
name: req.files[0].originalname,
url: req.files[0].path,
id: "",
};
console.log(req.files[0].originalname);
Video.find({ name: test.name }, (err, cb) => {
if (err) {
res.json({
error: true,
message: `There was a problem uploading the video because: ${err.message}`,
});
} else {
let file = {
name: req.files[0].originalname,
url: req.files[0].path,
id: "",
};
cloud
.uploads(file.url)
.then((result) => {
Video.create({
name: req.files[0].originalname,
url: result.url,
id: result.id,
});
})
.then((result) => {
res.json({
success: true,
data: result,
});
})
.catch((err) => {
res.json({
error: true,
message: err.message,
});
});
}
});
},
};
Multer config
const multer = require("multer"),
path = require("path");
//multer.diskStorage() creates a storage space for storing files.
const imageStorage = multer.diskStorage({
destination: (req, file, cb) => {
if (file.mimetype === "image/jpeg" || file.mimetype === "image/png") {
cb(null, path.join(__dirname, "../files"));
} else {
cb({ message: "This file is not an image file" }, false);
}
},
filename: function (req, file, cb) {
cb(null, file.originalname);
},
});
const videoStorage = multer.diskStorage({
destination: (req, file, cb) => {
if (file.mimetype === "video/mp4") {
cb(null, path.join(__dirname, "../files"));
} else {
cb({ message: "This file is not in video format." }, false);
}
},
filename: (req, file, cb) => {
cb(null, file.originalname);
},
});
module.exports = {
imageUpload: multer({ storage: imageStorage }),
videoUpload: multer({ storage: videoStorage }),
};
When uploading files to Cloudinary, the maximum size of the request body can be 100MB. Any request that is larger than this would receive the 413 error you are seeing. To upload files larger than 100MB, these need to be sent in chunks.
Since you are using the Cloudinary NodeJS SDK, you can update your code to use the upload_large method for your uploads instead of the regular upload method.
The upload_large method should be used for all files >100MB as it splits the file and uploads it in parts automatically for you. That said, you can also use this uplaod_large method for all files, even if they are small in filesize and those would work as well.
It takes the exact same parameters as the upload method and also optionally accepts a chunk_size (default 20MB).

am not able to upload image from react native to nodejs server even i can upload image from postman,

am using "react-native-image-picker": "^3.2.1", to get images from the library am getting it, but am not able to upload it to nodejs server using multer although I can upload an image from postman it means it should work fine
here is my react native code
this.setState({ uri: response.uri });
const bodyToBe = new FormData({ maxDataSize: 20971520 });
bodyToBe.append('photo', {
type: response.type,
uri: response.uri,
name: response.fileName
})
fetch('http://192.168.10.6:5000/api/open/upload-any-image', {
headers: {
Authorization: `Bearer ${this.props.user.userToken}`,
'Accept': 'multipart/form-data',
'Content-Type': 'multipart/form-data',
},
method: 'POST',
body: bodyToBe
})
.then(response => {
console.log(response, "this is response");
response.json().then(res => console.log(res, "its is")).catch(err => console.log(err, "here you go"));
})
.catch(e => {
console.log(e.toString(), "error")
});
and server-side multer config is
'use strict;
const multer = require('multer');
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './uploads');
},
filename: function (req, file, cb) {
cb(null, Date.now() + file.originalname);
}
});
const fileFilter = (req, file, cb) => {
// reject a file
if (file.mimetype === 'image/jpeg' || file.mimetype === 'image/png') {
return cb(null, true);
} else {
return cb(null, false);
}
};
const upload = multer({
storage: storage,
limits: {
fileSize: 1024 * 1024 * 25
},
fileFilter: fileFilter
});
module.exports = upload;
and the express route is
console.log("request =>" ,req.files)
return openService
.uploadImage(req.body, req.files, req.user)
.then((data) => {
res.send(RS.successMessage(data))
})
.catch((err) => next(err));
});
Thanks in advance for helping.

How to loop into multiple fieldname to get the files.path

I have Node.js app, served by express, with my frontend being made with React.js. My issue is i got to different fieldname for my images. Cover Photo and Avatar Photo. I'm having hard time to figure out how to loop into to different fieldname and get the path of the image. The result that i want is the backend will res.send(path of the image either avatar or cover or both of them).
// imageuploadroutes
import express from 'express';
const router = express.Router();
import multer from 'multer';
import path from 'path';
const storage = multer.diskStorage({
destination: function (req, file, cb) {
if (file.fieldname === 'coverPhoto') {
cb(null, 'public/images/cover');
} else {
cb(null, 'public/images/avatar');
}
},
filename: function (req, file, cb) {
cb(
null,
`${file.fieldname}-${Date.now()}${path.extname(file.originalname)}`
);
},
});
const upload = multer({
storage,
limits: {
fileSize: '2mb',
},
fileFilter: (req, file, cb) => {
if (
file.mimetype == 'image/png' ||
file.mimetype == 'image/jpg' ||
file.mimetype == 'image/jpeg'
) {
cb(null, true);
} else {
cb(null, false);
return cb(new Error('Only .png, .jpg and .jpeg format allowed!'));
}
},
});
router.post(
'/user/profile',
upload.fields([
{
name: 'coverPhoto',
maxCount: 1,
},
{
name: 'avatarPhoto',
maxCount: 1,
},
]),
function (req, res) {
var file = req.files[Object.keys(req.files)[0]];
console.log(file)
}
);
export default router;
Result
[
{
fieldname: 'avatarPhoto',
originalname: 'Screen Shot 2021-03-02 at 11.49.56 AM.png',
encoding: '7bit',
mimetype: 'image/png',
destination: 'public/images/avatar',
filename: 'avatarPhoto-1614704247624.png',
path: 'public/images/avatar/avatarPhoto-1614704247624.png',
size: 597941
}
]
but the problem is I can't get the .path
The file is an array, you should iterate over it:
var file = req.files[Object.keys(req.files)[0]];
console.log(file);
file.forEach(fileData => {
console.log(fileData.path);
})

Error uploading multiple images in node.js

I am trying to upload images in mongo db but after clicking on send in postman it shows "img": null
I am using flutter for frontend so I want to make a rest api I am able to upload single image but when I am trying to upload multiple images it shows
"img": null
I have also created a schema
where I have set
img:{
type: array,
default:"",
}
const express = require("express");
const router = express.Router();
const Profile = require("../models/profile.model");
const middleware = require("../middleware");
const multer = require("multer");
const path = require("path");
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, "./uploads");
},
filename: (req, file, cb) => {
cb(null, req.decoded.username + ".jpg");
},
});
const fileFilter = (req, file, cb) => {
if (file.mimetype == "image/jpeg" || file.mimetype == "image/png") {
cb(null, true);
} else {
cb(null, false);
}
};
const upload = multer({
storage: storage,
limits: {
fileSize: 1024 * 1024 * 6,
},
// fileFilter: fileFilter,
});
//adding and update profile image
router
.route("/add/image")
.patch(middleware.checkToken, upload.array("img",5), (req, res) => {
Profile.findOneAndUpdate(
{ username: req.decoded.username },
{
$set: {
img: req.files.path,
},
},
{ new: true },
(err, profile) => {
if (err) return res.status(500).send(err);
const response = {
message: "image added successfully updated",
data: profile,
};
return res.status(200).send(response);
}
);
});
when you upload multiple images, multer create a array of object like this :
req.files : [{…}, {…}, {…}]
that one of the property of objects is path, so there are many way to insert to path in img.
if type of img defined array [] in schema you can do like this in findOneAndUpdate :
{
$set: {
img: req.files.map(file => file.path),
},
}

upload files from different fields in a form using multer

I have a document that contains two fields are of input type="file" and I want to upload both of these on submit.
This post method giving me internal server error 500 on uploading two files but when I upload one file, it is OK.
router.post('/', mediaFiles.uploadSingle('icon_url'), mediaFiles.uploadSingle('background_url'),
async (req, res) => {
name: req.body.name,
icon_url: req.file.path.replace(/\\/g, "/"), // req.file['icon_url']
background_url: req.file.path.replace(/\\/g, "/") // req.file['background_url']
})
you can ignore this MediaFiles class because it provides traditional code to upload images with multer
import multer from "multer";
import path from "path";
class MediaFiles {
private storage = multer.diskStorage({
destination: 'uploads/',
filename: function (req, file, callback) {
callback(
null,
file.originalname.replace(/\.[^/.]+$/, "") + '-' + Date.now() + path.extname(file.originalname))
}
})
uploadSingle(fieldName?: string) {
try {
return multer({
storage: this.storage,
limits: { fileSize: 1024 * 1024 * 1 }, // 1MB = 1024 * 1024 * 1
fileFilter: function (req, file, callback) {
const fileTypes = /jpeg|jpg|png/;
const extName = fileTypes.test(path.extname(file.originalname).toLowerCase());
const mimeType = fileTypes.test(file.mimetype);
if (extName && mimeType) {
callback(null, true)
} else {
callback(new Error('Error: Images Only!'), null)
}
}
}).single(fieldName);
} catch (err) {
console.log(err.message)
}
}
}
export default new MediaFiles();
I don't think you could have two multer objects, I was having the same problem and here is what worked for me.
const storage = multer.diskStorage()
const mediaFiles = multer({
storage:storage })
.fields([{ name: 'icon_url', maxCount: 1 }, { name: 'background_url', maxCount: 1 } ]
router.post('/', mediaFiles, async (req, res) => {
console.log(req.files) // req.files is an array of files
}

Resources