Upload multiple files in node.js using multer - node.js

I am creating a node.js app in which there will be an option of uploading the documents.
The front-end Scenario: There will be three fields 1) profile picture 2) user's ID card no 1 (eg. PAN card) 3) user's Id card no 2 (eg. AADHAR card) -> this all field will be in a single page
Now the concern is whenever user uploads the documents I want to save it in a such a way that profile_picture should be considered as 0, user's ID card no 1 should be considered as 1 and so on.
The user schema:
const userSchema = new mongoose.Schema(
{
profile_picture: { type: Array },
documents: {
type: Array,
},
...
{
timestamps: true,
}
);
The uploadDocument service function:
exports.uploadDocuments = async (_id, file) => {
let document = await User.findByIdAndUpdate(
{ _id },
{
$set: { registration_process_value: 99 },
$push: file, //The actual problem is here
},
{ new: true }
);
return document;
};
the controller:
exports.uploadDocuments = catchAsync(async (req, res) => {
try {
check_user = await getUser.getUser(req.data.id);
if (!check_user) return res.status(404).json({ message: "User not found" });
if (check_user.registration_process_value >= 4) {
let uploadDocument = await userService.uploadDocuments(
check_user.id,
req.files
);
return res.status(200).json({ data: uploadDocument });
}
return res.status(404).json({ message: "You are not a verified user" });
} catch (error) {
return res.status(400).json({ message: error });
}
});
The multer function:
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "./src/uploads/");
},
filename: function (req, file, cb) {
cb(
null,
file.fieldname + "-" + Date.now() + path.extname(file.originalname)
);
},
});
var upload = multer({
storage: storage,
fileFilter: function (req, file, cb) {
var filetypes = /jpeg|jpg|png|pdf/;
var mimetype = filetypes.test(file.mimetype);
var extname = filetypes.test(path.extname(file.originalname).toLowerCase());
if (mimetype && extname) {
return cb(null, true);
}
cb("Please upload valid file");
},
}).fields([
{ name: "documents", maxCount: 2 },
{ name: "profile_picture", maxCount: 1 },
]);
I literally have no idea how to accomplish that. Can anyone assist me here?

Related

how to upload image files to server and MongoDB

React.js Node.js Express.js Axios Multer MongoDB Mongoose
Wrote this form to register users, the user enters name, email, password, and a file for later use as profile pic/Avatar.
When i tested the form on Postman the opposite has happened, the file was uploaded to the public/uploads/images folder but it didnt post to the user with the rest of the registration data i entered.
But when i tested the form on localhost domain the image filename was saved on the user's Avatar value MongoDB nut was'nt uploaded to the servers folder i chose to upload my uploaded files.
wanted end result:
to register user to websites database with all parameters, uploading the image to the server and image filename to users avatar data
Register Route
router.post("/register", upload.single("avatar"), async (req, res) => {
try {
const validatedValue = await validateRegisterSchema(req.body);
const user = await findUserByEmail(validatedValue.email);
if (user) throw "try different email";
const hashedPassword = await createHash(validatedValue.password);
validatedValue.password = hashedPassword;
await createNewUser(validatedValue);
res.status(201).json({ msg: "user created"});
} catch (error) {
res.status(400).json({ error });
}
});
Multer
destination: (req, file, cb) => {
cb(null, "./public/uploads/images/");
},
filename: function (req, file, cb) {
crypto.pseudoRandomBytes(16, function (err, raw) {
if (err) return cb(err);
cb(null, file.originalname);
});
},
});
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,
limit: {
fileSize: 1024 * 1024 * 10,
},
fileFilter,
});
User Model
const Schema = mongoose.Schema;
const usersSchema = new Schema({
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
wishList: { type: Array },
isAdmin: { type: Boolean, default: false },
avatar: { type: String },
});
const Users = mongoose.model("users", usersSchema);
const createNewUser = (userData) => {
const newUser = new Users(userData);
return newUser.save();
Solved
prior code:
const handleAvatarChange = (ev) => {
let newUserInput = JSON.parse(JSON.stringify(userInput));
newUserInput[ev.target.name] = ev.target.files[0].name;
setUserInput(newUserInput);
};
sulution:
const handleAvatarChange = (ev) => {
let newUserInput = JSON.parse(JSON.stringify(userInput));
newUserInput[ev.target.name] = ev.target.files[0]; // removed ".name" left it as file object
setUserInput(newUserInput);
};

Uploaded image with Multer using MERN stack disappears after an hour or two

I am trying to upload an image using multer. The site already deployed in vercel.com which comes with free hosting. The code works well and the images can definitely be uploaded and be seen after the successful upload. However, after 1 hour or two, the uploaded images are gone.
Here is the code in my API.
//--------------------------------- ROUTE
const multer = require('multer');
const Storage = multer.diskStorage({
destination: 'uploads',
filename:(req,file,cb)=>{
cb(null, file.originalname);
},
});
const upload = multer.({
storage:Storage
}).single('testImage')
router.post('/upload', (req,res) => {
upload(req,res,(err)=>){
if(err){
console.log(err)
}else {
const newImage = new
}
}
})
const storage = multer.diskStorage({
destination: function (req, file, callback) {
callback(null, path.join(__dirname, '../images/'))
},
filename: function(request, file, callback){
callback(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname))
}
})
const upload = multer({
storage: storage,
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('/create', AUTHENTICATE, AUTHORIZE, upload.single('image'), (req, res) => {
const url = req.protocol + '://' + req.get('host')
ProductController.INSERTPRODUCT(req.body, req.file, url).then(resultFromController => res.send(resultFromController))});
//--------------------------------- CONTROLLER
module.exports.INSERTPRODUCT = (productData, reqFile, url) => {
let newProduct = new Product({
name: pname,
description: desc,
price: price,
isActive : act,
image: url + "/images/" + reqFile.filename
});
return newProduct.save().then((product, err) => {
if (product) {
return product;
} else {
return err;
};
}).catch(error => error)
};
const mongoose = require('mongoose');
//--------------------------------- SCHEMA
const productSchema = new mongoose.Schema({
name: {
type: String,
unique: true,
required: [true, 'Product Name is Required']
},
description: {
type: String,
unique: true,
required: [true, 'Description is Required']
},
price: {
type: Number,
required: [true, 'Product Price is Required']
},
image: {
data:Buffer,
contentType: String
},
isActive: {
type: Boolean,
default: true
},
createdOn: {
type: Date,
default: Date.now
}});
module.exports = mongoose.model('Product', productSchema);
The thing is, it was deployed in heroku and the front end is in vercel. I asked a few friends and they said that since it requires a dedicated storage, it is an add on to hosting platforms already. Which means the hosted site has to be paid. I was just thinking thay maybe, maybe there is a way that the uploaded images won't be gone after being uploaded without having an add on to hosting platforms.

not updating if file is not selected in nodejs using multer

I am trying to update the data. It's working fine if I select the file but there is a problem when I just want to update any field excluding file input type. I am not able to update in such a condition.
How can I resolve it?
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './public/uploads/')
},
filename: function (req, file, cb) {
cb(null, file.originalname+Date.now()+path.extname(file.originalname))
}
});
var upload = multer({
storage:storage,
});
app.post('/editProfile', auth, upload.single('image'), async (req, res, next) => {
try {
const userEmail = req.user.email;
const name = req.body.name;
const filename = req.file.filename;
const contact = req.body.contact;
console.log(filename + "fghj");
if(filename) {
const edited = await User.updateOne({ 'email': userEmail }, {
$set: {
name: name,
contact: contact,
filename:filename
}
});
}
else {
const edited = await User.updateOne({ 'email': userEmail }, {
$set: {
name: name,
contact: contact,
}
});
}
res.redirect('profile');
}
catch (e) {
console.log(`while edit profile ${e}`);
res.status(400).send(e);
}
})
You are trying to get filename but remember you didn't send a file in your scenario. Here:
const filename = req.file.filename;
First, you should check if a file is exist or not.
You can revise your code like this:
app.post('/editProfile', auth, upload.single('image'), async (req, res, next) => {
try {
const userEmail = req.user.email;
const name = req.body.name;
// const filename = req.file.filename; Remove this line from here
const contact = req.body.contact;
if (req.file) {
const filename = req.file.filename // And, use that code when you make sure that you have a file
const edited = await User.updateOne({ 'email': userEmail }, {
$set: {
name: name,
contact: contact,
filename: filename
}
});
}
else {
const edited = await User.updateOne({ 'email': userEmail }, {
$set: {
name: name,
contact: contact,
}
});
}
res.redirect('profile');
}
catch (e) {
console.log(`while edit profile ${e}`);
res.status(400).send(e);
}
})

why image is saving as text file in node js

Here i'm trying to save the image in database using multer but image type is saving as a text format but not in .png , .jpeg, .jpg format,
PLease help me where i'm doing wrong thanks in advance
Schema:-
module.exports = mongoose => {
const Role = mongoose.model(
"role",
mongoose.Schema(
{
roleType : { type:String },
image: { type: String,
data: Buffer}
}
)
);
return Role;
};
controller (Creating an instance):-
exports.addRoleFields = async (req, res) => {
const rolesList = new Role ({
roleType : req.body.roleType,
roleImg : req.file.path,
});
rolesList
.save(rolesList)
.then(data => {
res.status(200).send({ data, statusCode: "200" });
})
.catch(err => {
res.status(500).send({
message: err.message || "Some error occurred while creating.",
statusCode: "500"
});
})
}
}
routes:-
module.exports = app => {
const multer = require("multer"),
storage = multer.diskStorage({
destination: function(req, file, cb) {
cb(null, 'uploads')
},
filename: function(req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
})
const uploadImg = multer({storage: storage}).single('image');
const roles = require("../controllers/roles.js");
var router = require("express").Router();
router.post("/addRole", uploadImg , roles.addRoleFields);
app.use('/api/roles', router);
};
I simply changed this
filename: function(req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
to
filename: function (req, file, cb) {
cb(null, file.originalname);
}
its working and saving the file
try this for mongodb client
const storage = multer.diskStorage({
destination: async function (req, file, cb) {
let path = 'uploads/' + req.body.path;
if (!fs.existsSync(path)) {
fs.mkdirSync(path, { recursive: true }, (err) => {
if (err) throw err;
});
}
await cb(null, path);
},
filename: function (req, file, cb) {
cb(null, req.body.filename)
}
});
var upload = multer({ storage: storage })
const router = express.Router();
// Upload Image
router.post("/upload", upload.single('image'), (req, res, next) => {
return res.json({
image: req.file.path
});
});
in this upload.single('image'), file should be the name in which formdata carries the file.
in your case,
router.post("/addRole", uploadImg('image'), (req, res)=>{
});
mongoose model
const imgSave = new mongoose.Schema({
img:{
data: Buffer,
contentType: String
}
});

file still uploads with multer even after failed form validation

I have a form for adding a product which lets a user input product name, description etc. and also allows an image upload.
In my app.js file which is my entry point, I have:
const fileStorage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'uploads');
},
filename: (req, file, cb) => {
cb(null, new Date().toISOString() + '-' + file.originalname);
}
});
const fileFilter = (req, file, cb) => {
if (
file.mimetype === 'image/png' ||
file.mimetype === 'image/jpg' ||
file.mimetype === 'image/jpeg'
) {
cb(null, true);
} else {
cb(null, false);
}
};
app.use(multer({ storage: fileStorage , fileFilter: fileFilter, limits: { fileSize: 100000} }).single('image'));
Here is my controller:
exports.postAddListing = (req, res, next) => {
const title = req.body.title;
const category = req.body.category;
const description = req.body.description;
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).render('account/add-listing', {
pageTitle: 'Add Item',
path: '/account/add-listing',
errorMessage: errors.array(),
successMessage: null,
oldInput: {
title: title,
description: description
}
});
}
const image = req.file;
const imageUrl = image.path;
const product = new Product({
title: title,
category: category,
description: description,
userId: req.user,
datePosted: Date.now(),
imageUrl: imageUrl
});
product.save()
.then(result => {
const successMessage = req.flash('success', 'Item sucessfully added');
res.redirect('/account/add-listing');
})
.catch(err => console.log(err));
};
I am using express-validator for form validation. The problem I have is that if I for example leave all fields empty but choose an image, validation will fire and I will get error messages but the image will still upload. If form validation fails I don't want the image to upload but not sure how to achieve that.

Resources