Save file's binary data in MongoDB - node.js

I have working file uploading function in multer. It was saving the file data as is. Now I would like to store the file data in the binary form. How can I do that?
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");
},
});
The upload document service file:
exports.uploadDocuments = async (_id, file) => {
let path = file.profile_picture.map((item) => {
return item.path;
});
if (file.profile_picture) {
document = await User.findByIdAndUpdate(
{ _id },
{ $set: { profile_picture: path.toString() } },
{ new: true }
);
}
if (file.documents) {
document = await User.findByIdAndUpdate(
{ _id },
{
$set: { registration_process_value: 99 },
$push: { documents: { $each: file.documents } },
},
{ new: true }
);
}
return document;
};
The controller file function:
let uploadDocument = await userService.uploadDocuments(
check_user._id,
req.files
);
In the schema type I have changed the field to Buffer from String.
It is storing profile_picture data into binary form but it is not saving documents data into binary form as I am sending two documents. and it is giving me the casing error:
"path": "documents",
"reason": null,
"name": "CastError",
"message": "Cast to Buffer failed for value \...\" (type Object) at path \"documents\""
}

Related

File upload in node.js using multer

I have created a multer function that uploads a file of following type "jpeg, png, jpg and pdf" in the documents field for uploading documents like PAN, aadhar card etc.(both routes are separate)
Now using that same multer function I want to give permission to user to upload their profile picture but that should be only in image format. It should not accept pdf or txt or any other file extension.
How can I do that?
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");
},
});
both uploading documents fields are different. For uploading documents the field is documents and for display picture it is profile_picture.
The uploadDocuments service:
exports.uploadDocuments = async (_id, file) => {
let document = await User.findByIdAndUpdate(
{ _id },
{
$set: { registration_process_value: 99 },
$push: { documents: { $each: file } },
},
{ new: true }
);
return document;
};

File data(Image, pdf) is not getting pushed into the MongoDB array

Whenever I upload the new file from the postman it overwrites existing file and save one and only uploaded file.
I have tried document.push method but it logs the error that "TypeError: documents.push is not a function" But when I log console.log(documents) it logs in an array. Am I doing something wrong?
The multer function to handle file uploading:
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");
},
}).array("documents");
The uploadDocument service file:
exports.uploadDocuments = async (id, documents, file) => {
let files = documents.push(file);
let document = await User.findByIdAndUpdate(
{ _id: id },
{ $set: { documents: files, registration_process_value: 99 } },
{ new: true }
);
return document;
};
The userController to upload the file:
exports.updateDocuments = catchAsync(async (req, res) => {
try {
check_user = await userService.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,
check_user.documents,
req.files
);
return res.status(200).json({ data: uploadDocument });
}
} catch (error) {
return res.status(400).json({ message: error });
}
});
The documents type is Array in the schema like following:
documents: {
type: Array,
}
documents.push(file) is returning a number (like if I console.log(files) after sending the request from the postman then it returns "files -> 2"). It is not pushing the actual data of the file.
First you push a file into documents and store the new length of the array in files:
let files = documents.push(file);
Then you set the documents field to that array length:
let document = await User.findByIdAndUpdate(
{ _id: id },
{ $set: { documents: files, registration_process_value: 99 } },
{ new: true }
);
I assume that you want to store the actual array:
{ $set: { documents: documents, registration_process_value: 99 } }
Instead of using $set to replace the entire documents array, I would suggest using $push:
{
$set: { registration_process_value: 99 },
$push: { documents : file }
}
EDIT: if file is actually an array of file objects, instead of a single object, things change a bit.
If you still want to use push:
documents.push(...file);
With $push, you need to use $each:
{
$push : { documents : { $each : file } }
}

Upload video/image file data in node.js and store it in MongoDB

I want to store Image/Video data that user posts into a mongoDB database but it is getting saved as an empty array.
The Multer Configuration:
const multer = require("multer");
const path = require("path");
const storage = multer.diskStorage({
destination: "./uploads/",
filename: function (req, file, cb) {
cb(
null,
file.fieldname + "-" + Date.now() + path.extname(file.originalname)
);
},
});
const upload = multer({
storage,
}).array("media");
module.exports = upload;
The createPost route to upload a new post that can be type of anything like plain-text, Images or videos[Media]:
exports.createPost = async (req, res) => {
try {
const user = await User.findById(req.user._id);
if (!user) return res.status(401).json({ message: "No user found" });
const { media, hashTags, postStatus } = req.body;
const mentions = await User.find(
{ User_name: req.body.mentions },
{ User_name: 1, _id: 0 }
);
if (
req.body.mentions &&
(!Array.isArray(mentions) || mentions.length === 0)
) {
return res.status(404).send("Please enter valid user name");
}
let payLoad = {
userId: req.user._id,
media,
hashTags,
postStatus,
};
if (mentions.length > 0) {
payLoad = { ...payLoad, mentions };
}
let new_post = await new Post(payLoad).save();
return res.status(200).send(new_post);
} catch (error) {
return res.status(500).send(error.message);
}
};
When I pass plain-text in media attribute then It is saved to the database but when I pass image or video from postman form-data then the media is getting saved as an empty array
The API endpoint:
router.post("/createPost", auth, storage, post.createPost);
Can anyone assist me here?

how to store files path in a user record?

I am trying to upload files to store in a user database but its not getting stored.
This is my schema.
const UserSchema = new mongoose.Schema({
email: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
},
file: {
type: String,
},
});
<--This is my route.I am using multer to handle multiform data -->
const storage = multer.diskStorage({
destination: "public/upload",
filename: function (req, file, cb) {
cb(
null,
file.fieldname + "-" + Date.now() + path.extname(file.originalname)
);
},
});
//Initialize Upload
const upload = multer({
storage: storage,
fileFilter: function (req, file, cb) {
checkFileType(file, cb);
},
}).single("file");
//Check File Type
function checkFileType(file, cb) {
// Allowed extensions
const fileTypes = /pdf/;
//Check extensions
const extname = fileTypes.test(path.extname(file.originalname).toLowerCase());
//Check mime
const mimetype = fileTypes.test(file.mimetype);
if (mimetype && extname) {
return cb(null, true);
} else {
cb("Error:Pdf only");
}
}
router.post("/user/:id/upload", async (req, res) => {
const _id = req.params.id;
try {
const user = await User.findById(_id);
if (!user) {
res.status(404).json({ msg: "No User Found" });
}
user.file = req.file;
upload(req, res, (err) => {
if (err) {
console.log(err);
} else {
console.log(req.file);
}
I am only able to store the files in the public folder.Is there a way to store files for a particular user in db so that I can know this user uploaded this file?
Multer doesn't save files directly in your database. It only stores them in your file disk system.
So instead of doing user.file = req.file you should save the destination + filename you created with multer in the database.
You're saving the filename as file.fieldname + "-" + Date.now() + path.extname(file.originalname) in "public/images" but in your database you're just saving req.file which is completely different.
First of all let me tell you that it's not the best practice to store a file itself in a db. The best practice is to store filepath to user's object so that you can track that which file uploaded by which user.
Let say you have a route like
router.post("/", log, upload.fields([{ name: 'userFile' }]), fileUpload);
and in your fileUpload function just check if files is present, and if file is present then save file's url in the db like this
function fileUpload(req,res){
const user;
if (req.files['userFile']) {
user.filePath = `public/upload/${req.files['userFile'][0].filename}`;
const userObj = new User(user);
userObj.save();
}
}
I just gave a rough implementation to just give you an idea that how can you achieve that.

How to passing params whit file upload and get it in node js Ionic 3

Server Node JS file upload whit multer :
var multer = require('multer');
var storage = multer.diskStorage({
destination: function (req, file, callBack) {
console.log(req.body);
callBack(null, 'public/images/');
}, filename: function (req, file, callBack) {
callBack(null, 'someName');
}
});
var upload = multer({ storage: storage }).single('file');
outer.post('/uploads',uploads.single('file'),
function(req, res) {
//console.log(JSON.stringify(req.files.file));
console.log('/////////////////////////////////');
console.log(JSON.stringify(req.body));
console.log(JSON.stringify(req.params))
console.log(req.files.file)
var base64Data = req.files.file.data.toString('base64').replace(/^data:image\/jpeg;base64,/, "");
//console.log(base64Data);
var time = Date.now().toString()+"out.jpeg" ;
fs.writeFile('public/images'+"/"+time, base64Data, 'base64', function(err) {
console.log(err +' §§§§§§§§§§§' );
});
res.status(204).end();
}
);
Frontend Ionic 3 :
var name = "upload";
var par = {
token : this.myToken ,
contenu_titre : this.contenu_titre ,
contenu_text : this.contenu_text ,
contenu_type : 'img' ,
} ;
let option: FileUploadOptions = {
params : par,
fileKey:'file',
mimeType:'image/jpeg',
httpMethod:'POST',
fileName:'user_step4#'+name
};
let loader = this.loadingCtrl.create({
content: "Uploading...."
});
loader.present();
const fileTransfer:FileTransferObject = this.transfer.create();
// console.log('filename'+this.curfilename);
fileTransfer.upload(this.photo ,encodeURI(this.linkPic+"/publication/uploads"),option).then((result)=>
{
alert('uploaded')
console.log('success');
console.log(result);
loader.dismiss();
}).catch(error=>{
loader.dismiss();
alert(error);
console.log('uploaderror');
console.log(error.message);
});
}
I want to get the Params values in the server ,
every time is undefined or null
i want to get some params whit my file to save the params in my database.
the upload is working fine but in not getting the params
req.body return {}
and the req.file return onlu the filename and the file
You can use params with FileTransferOptions to send parameters along with your file.
Use mimeType: "multipart/form-data" to specify that this request contains multiple type of data
var options =
{
fileKey: "file",
fileName: filename,
chunkedMode: false,
mimeType: "multipart/form-data",
params: {
"full_name": this.userForm.value.u_name,
"email": this.userForm.value.u_email,
"country": this.userForm.value.u_country,
"state": this.userForm.value.u_state,
"city": this.userForm.value.u_city,
"pincode": this.userForm.value.u_pincode,
"fax": this.userForm.value.u_fax,
"address": this.userForm.value.u_address,
}
};
transfer.upload(this.photo, this.yourURL, options).then(data =>
{
//Handle the response from the server
}

Resources