Images are not storing in Database using multer - node.js

I am trying to store image in local folder and save image name in mongodb using multer with the below code.
var uploadDir=__dirname+ '/assets/images';
var images='.jpg';
var storage=multer.diskStorage({
destination:function(req, file, cb){
cb(null, uploadDir);
},
filename:function(req, file, cb){
console.log(file);
image=Date.now()+images;
callback(null, images);
}
});
var upload=multer({storage:storage}).single('img');
But its not storing image in local folder and only its saving .jpg string in image field in mongodb. I think the problem is that filename: method is not working. Please review it and help me to find the solution.
Thanks,

Your error is in the multer filename configuration. You were using the images variable in there and that's why wasn't storing the image in the right path and only with the .jpg name. It is a good idea to define the var image as var, otherwise will be defined in the global namespace with side effects that you can not predict. This should work:
var uploadDir=__dirname+ '/assets/images';
var images='.jpg';
var storage=multer.diskStorage({
destination:function(req, file, cb){
cb(null, uploadDir);
},
filename:function(req, file, cb){
console.log(file);
var image=Date.now()+images;
callback(null, image);
}
});

Related

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.

nodejs: Retrieving base64 Images from Mongodb using Postman

Looking for help on Uploading and Retrieving Images from MongoDb using multer.
My front end is ReactNative.(Not sure if this is needed but just to be sure.)
Multer
Problem: After looking and following tutorials i'm able to encode my path to base64 and upload it to my DB but now i'm confused how to retrieve the file from my DB. I saw some tutorials about decoding it from base64 but I don't quite understand how do I go about retrieving an image and displaying it in postman. (I tried looking but haven't found anything that gives me an answer. I'm sorry if this is a duplicated question. If you could point me in a direction or give me some advice I would be really greatful.)
**POST**
route.post("/sad", upload.single("image"), (req, res, next) => {
console.log(req.file);
const img = fs.readFileSync(req.file.path);
const img_enc = img.toString('base64');
const obj = {
usrImage: {
data: new Buffer.from(img_enc, 'base64'),
contentType: "image/jpg",
},
};
console.log(obj);
const newAccout = new account(obj);
newAccout.save();
});
**RETRIEVE**
route.get('/sad',(req,res)=>{
img.find({}).then((img)=>{
res.json(img)
//How do decode my buffer to show an image in Postman?
})
}
)
I am trying to create a userprofile where a username,password and image is saved. If you can help save an Image and then retrieve it from my accounts collection.
Hey I would advise that you start using a 3rd party for file upload like cloudinary very good way of managing files i.e images or video...
I am not that well of with multer but I can give a quick code example using Formidable does the same work as multer
Before you can start you'd need to make an account on cloudinary.com(don't worry its free)
Code below is how you could handle file upload
const Formidable = require("formidable"); //Meant for body parsing
const cloudinary = require("cloudinary").v2; // file uploader
//This below is your connection/configuration to get access to your cloudinary account so cloud_name, api_key and api_secret you'll get in your home dashboard(Cloudinary)
cloudinary.config({
cloud_name: process.env.CLOUD_NAME,
api_key: process.env.API_KEY,
api_secret: process.env.API_SECRET,
});
router.post('/api/file-upload', (req, res)=>{
const form = new Formidable.InconmingForm();
form.parse(req, (error, fields, files)=>{
const {file} = files
cloudinary.uploader.upload(file.path, {folder:"/"}, (err, res)=>{
const file_url = res.secure_url //This would be the url for your file given back by cloudinary
})
})
})
This script should upload your file and the file_url will be having the url of the file that you upload having ssl then after that you can now continue saving to mongoDB
Cloudinary docs for NodeJS
https://cloudinary.com/documentation/node_integration
Nice clear and understandable docs
Shameless plug
If you get lost you can check this video out on YouTube that I made handling file upload with cloudinary then save url given back to mongoDB
https://youtu.be/mlu-tbr2uUk
First call api find one
you will need fs module to complete following query
const fs = require('fs');
let data = await db.user.findOne({
where: {
id = req.body.id
}
})
// _________________ base 64 string data from findone query data
// |
let buff = new Buffer(data.image, 'base64');
let name = name.jpeg
let path = `tmp/${name}`; // <--- destination and file name you want to give to your file
fs.writeFileSync(path, buff);// < --this will write file to given path
fs.readFile(path, function (err, content) {// <------to send file in postman response
if (err) {
res.writeHead(400)
console.log(err);
res.end("No such image");
} else {
//specify the content type in the response will be an image
res.writeHead(200);
res.end(content);
}
});
fs.unlink(path, (err) => { // <-----to delete file from tmp directory
if (err) {
console.log(err)
}
})
Try this and switch to preview tab in postman.
I haven't tried it but maybe it helps.
route.get('/sad',(req,res)=>{
img.find({}).then((img)=>{
res.setHeader('contentType','image/jpg').send(img)
})
})

nodejs multer retrieve stored images to the client side

I have created file storage in nodejs application to store images in uploads folder. which works fine but now I want to display those images I have read some other posts but I am still quite unsure.
Here is my code:
var Storage = multer.diskStorage({
destination: function(req, file, callback) {
var pathname = file.originalname;
var path = pathname[0].replace('_','/');
cb(null,'./uploads'+pathname);
},
filename: function(req, file, callback) {
var pathname = file.originalname;
var filename = pathname[1];
if(pathname!=undefined)
callback(null, pathname);
}
});
var upload = multer({ storage: Storage }).single('file');
router.post('/upload', multer({dest:'./uploads/'}).single('file'), function(req,res)
{
return res.status(201).json({result:req.file});
});
from console log I get
{ fieldname: 'file',
originalname: '1569402978357.jpg',
encoding: '7bit',
mimetype: 'image/jpeg',
destination: './uploads/',
filename: 'ada9282345565e8a77c6adc4b2d15836',
path: 'uploads\\ada9282345565e8a77c6adc4b2d15836',
size: 170272 }
and in the uploads it is stored as filename
my problem is how can I display this image back? should call it from stored filename or should I change the storage to save it as original filename with file extension?
The choice to keep the original file name differs from use case to use case. In either case you will have to store the name somewhere in a persistence medium (like a database) so that while displaying it back you can look into your uploads directory and send the file back.
Depending on your use case, if you want to store the files in a different name, you need a way to find the files at a later stage. It can be achieved by storing the names in a database or you could even use some kind of formula to find out the file name of the stored file from the original one.
E.g:
name_of_stored_file = md5(name_of_original_file)
As files (images) are now stored in your backend, you can expose some API to send the files to client on request. Again this completely depends on the use case, but here's a simple example of using Expressjs res.sendFile method:
app.get('/file/:fileName', function (req, res) {
const filePath = // find out the filePath based on given fileName
res.sendFile(filePath);
});
http://expressjs.com/en/api.html#res.sendFile

How do I upload images using MongoDB + Node.js (Express.js)?

I also use Mongoose, if that is relevant. I am trying to allow users to upload a profile picture. There must be a simple way, isn't there?
I think you should try multer.
Simple from multer site:
var multer = require('multer')
var upload = multer({ dest: 'uploads/' })
app.post('/upload', uploads.any(), function(req,res){
res.send(req.files);
});
It should upload file in your uploads folder (under root), and return file in JSON.
In this example you will see how to store the file you are sending in to your server directory and then pick them up from there and save them. You can also directly save them. First you pick up the file using angular, you can use anything, if you want you can check here for more details. Here is my small example the code is in jade.
<input type="file" name="file" onchange="angular.element(this).scope().selectFile(this.files)"/>
<button ng-click="savePhoto()">Save </button>
In your angular controller
$scope.savePhoto = function () {
var fd = new FormData();
fd.append("file", $scope.files[0]);
)) ;
$http.post("/xxx/photos", fd, {
withCredentials: true,
headers: { 'Content-Type': undefined },
transformRequest: angular.identity
}).success(function (data) {
$scope.image = data; // If you want to render the image after successfully uploading in your db
});
};
Install multer using npm in your back end. And then in app.js you can set up a middleware to collect the files you are sending in. Just do console.log(req) here to check if you are getting the files till here. Multer does the magic here.
app.use(multer({
dest: path.join(__dirname, 'public/assets/img/profile'),
rename: function (fieldname, filename, req, res) {
console.log(req)// you will see your image url etc.
if(req.session.user) return req.session.user.id;
}
}));
So here the image will be stored in this path (public/assets/img/profile) in your server. Now you pick up the file from this server and add to your db.
var path = require('path');
var imgPath =path.join(__dirname, '../public/assets/img/profile/' + id + '.jpg'); // this is the path to your server where multer already has stored your image
console.log(imgPath);
var a ;
a = fs.readFileSync(imgPath);
YourSchema.findByIdAndUpdate( id, {
$set:
{'img.data' : a,
'img.contentType' : 'image/png' }
}, function(err, doc) {
if (err)console.log("oi");
}
);
//In case you want to send back the stored image from the db.
yourSchema.findById(id, function (err, doc) {
if (err)console.log(err);
var base64 = doc.img.data.toString('base64');
res.send('data:'+doc.img.contentType+';base64,' + base64);
});

Uploading images with fetch to Express using Multer

I'm attempting to upload images to an Express server. I'm not exactly sure about how to do this, but heres what I've got from what I've been able to pick up from MDN, express, react-dropzone, and multer Documentation. Multer does not seem to pick up the FormData object from react-dropzone, when logging out req.file it returns undefined.
server.js
var storage = multer.diskStorage({
destination: './public/users',
filename: function (req, file, cb) {
switch (file.mimetype) {
case 'image/jpeg':
ext = '.jpeg';
break;
case 'image/png':
ext = '.png';
break;
}
cb(null, file.originalname + ext);
}
});
var upload = multer({storage: storage});
app.use(upload.single('photo'));
app.post('/uploadUserImage', function (req, res) {
console.log(JSON.stringify(req.body.photo)) // form fields
console.log(req.photo) // form files
console.log(req.file) // form files
res.send(req.body.photo);
});
client.js
function uploadImage (image) {
var formData = new FormData();
formData.append('photo', image);
fetch('http://localhost:8080/uploadUserImage/', {
method:'POST',
body: formData
});
}
When I make this request morgan logs out the following:
{ photo: '[object File]' } <--- from console.log(req.body');
undefined <--- from console.log(req.file);
multer creates the folder public/uploads but does not place the image in the location. How can I get the photo because I need to run it through sharp (to compress the filesize and resize the image) and then place it in the uploads folder?
The error occurs because you specified the 'Content-type' explicitly. To do this properly, you'd also need to specify the boundary. You can find a detailed explanation of multipart/form-data here: How does HTTP file upload work?
To solve the issue with the file upload, you should remove the 'Content-Type' specification from the fetch request. You can also refactor the uploadImage method to upload the form without parsing the inputs:
function uploadImage () {
// This assumes the form's name is `myForm`
var form = document.getElementById("myForm");
var formData = new FormData(form);
fetch('http://localhost:8000/uploadUserImage', {
method: 'POST',
body: formData
});
}
The problem for me was that firebase has an error and can't use multer. You need to use busboy and parse it manually. Also I needed to append the uri from react native imagePicker instead of the file blob. Like this:
data.append('fileData', {
uri : pickerResponse.uri,
type: pickerResponse.type,
name: pickerResponse.fileName
});

Resources