Using node.js and mongodb I want to upload image and show that image using it's id.
but When i run it, showing an error..
Error: Failed to lookup view "/showImage" in views directory "H:\NodeJS\AddImage
\views"
searching a lot but couldn't find any proper and working solution for me.
what's the problem??
can anyone help??
thanks..
here is my code...........
app.js
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var path = require('path');
var multer = require('multer');
app.use(bodyParser.json());
app.use(express.static('public'));
var imagefile = require('./routes/imagefile');
app.set('view engine', 'ejs');
mongoose.connect('mongodb:..url');
imagefile(app);
app.listen(3000);
console.log('Running on port 3000');
imagefile.js
var express = require('express');
var multer = require('multer');
var mongoose = require('mongoose');
var fs = require('fs');
var imageSchema = mongoose.Schema({
img: { data: Buffer, contentType: String },
imageName : String
});
var Item = mongoose.model('Clothes',imageSchema);
var storage = multer.diskStorage({
destination: function(req, file, cb) {
cb(null, 'public/')
},
filename: function(req, file, cb) {
cb(null, file.originalname);
}
});
var upload = multer({
storage: storage
});
module.exports = function (app) {
app.get('/', function(req, res, next) {
res.render('index.ejs');
});
app.get('/images/:id', function(req, res) {
Item.findById(req.params.id, function (error, result) {
//res.contentType(result.contentType);
console.log(result.imageName);
//res.end(result.image.buffer, "binary");
res.render('/showImage',{imageName : result.imageName, imageId : result.imageName});
});
});
app.post('/', upload.any(), function(req, res, next) {
var newItem = new Item();
newItem.img.data = fs.readFileSync(req.files[0].path)
newItem.img.contentType = 'image/png';
newItem.imageName = req.files[0].originalname;
newItem.save();
res.render('index.ejs');
});
};
index.ejs
<html>
<head>
<title>test</title>
</head>
<body>
<form action "/" method="POST" enctype="multipart/form-data">
<input type="file" name="myimage" ></input>
<input type="submit" name="submit" value="submit"></input>
</form>
</body>
</html>
showImage.ejs
<html>
<head>
<title>test</title>
</head>
<body>
<h1><%= imageName %></h1>
<h1><%= imageId %></h1>
<div class="header">
<img src='/public/36417514_2140268509321308_7450232816341614592_n.jpg %>' />
</div>
</body>
</html>
Remove the leading slash in this function:
app.get('/images/:id', function(req, res) {
// Rest of the code
// ...
res.render('showImage', // <-- Remove slash
{imageName : result.imageName, imageId : result.imageName});
});
});
the problem is that it looks for file named '/showImage.ejs'.
When i upload my form (which just contains an image), the image goes in the root folder, but I would like it to go to /public/images. I have a separate routes.js file to handle routes. This is how I've set up multer (in my routes.js file).
var multer = require('multer');
var upload = multer({dest: '/public'});
The route for the POST request looks like this:
app.post('/upload', isLoggedIn, upload.single('file'), function (req, res) {
var file = __dirname + req.file.filename;
fs.rename(req.file.path, file, function (err) {
if (err) {
console.log(err);
res.send(500);
} else {
res.json({
message: 'File uploaded successfully',
filename: req.file.filename
});
console.log(file);
}
});
});
, and the form itself looks like this (it's an ejs file):
<form method="post" action="/upload" enctype="multipart/form-data">
<label for="profilepicture">Profile picture</label>
<input type="file" name="file" accept="image/*">
<input type="submit" value="change profile picture">
</form>
You are providing a wrong path in the dest, it's a relative path so it should be dest: 'public/' instead of dest: '/public'
Also, you are moving the file from the public folder by using fs.rename and the reason it is moved to outside the root folder is you are adding the root folder in the filename and not as a path :
var file = __dirname + req.file.filename;
should be :
var file = __dirname + '/' + req.file.filename;
or even better :
var file = path.join(__dirname, req.file.filename);
Overall, a working script with no need for the fs.rename :
var multer = require('multer');
var upload = multer({dest: 'public/'});
app.post('/upload', isLoggedIn, upload.single('file'), function (req, res) {
res.json({
message: 'File uploaded successfully',
filename: req.file.filename
})
})
I am trying to build an application that consists of uploading a file(such as an image) and posting it.
this is what I have done so far:
var express = require('express');
var multer = require('multer');
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './public/img');
},
filename: function (req, file, cb){
cb(null, file.originalname + '-' + Date.now());
}
});
var upload = multer({storage: storage});
So this code above will save the files I upload them in a folder called 'img'
module.exports = function(app){
app.get('/', function(req, res){
res.render('index');
});
app.post('/upload', upload.single('file'), function(req, res){
res.send(req.file);
});
}
Now in the last post request I get all the metadata information about the file in 'req.file'. I wanted to get the file and post it if someone, for instance, makes this request:
app.get('/postedfiles', function(req, res){});
should I save them in a database or something?
Not really, it saves inside your computer, inside the directory that you choose.
This is the plain html form for the multer upload.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<form accept="image/x-png,image/gif,image/jpeg" enctype="multipart/form-data" action="/profile" method="post">
<input type="file" name="avatar" value="">
<input type="submit" name="" value="ssss">
</form>
</body>
</html>
This is our backend code. Inside storage, I choose where to upload the files, which is under /upload directory, and give them file names of that current time. We declare out upload variable for set up, and then we use upload.single('avatar') while we're getting a post request, we declare it right before the callback. What avatar here is that it's the file name from out html form inside input tag. And in the callback we can get to our file by using req.file. The module saves the file this way, very easy to use.
var express = require('express')
var multer = require('multer')
var app = express()
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, __dirname + '/uploads') //you tell where to upload the files,
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now() + '.png')
}
})
var upload = multer({storage: storage,
onFileUploadStart: function (file) {
console.log(file.originalname + ' is starting ...')
},
});
app.set('view engine', 'ejs');
app.get('/', function(req, res, next){
res.render('mult'); //our html document
})
app.post('/profile', upload.single('avatar'), function (req, res, next) {
// req.file is the `avatar` file
console.log(req.file);
return false;
})
Make sure, you give the images and extension of either png or jpeg, or whatever you want to use, otherwise it will not be considered as an image in the computer.
Update on your question
If you want to show the client the image without refreshing the page, just use AJAX with a get request on the client browser. You can upload the files inside your web server or to a web server and retrieve images from there. For example, my profile picture in stackoverflow is saved here
You can use params in a get request to receive all the files from server.
For example, imagine a client making a get request to /uploads/imageOfApet.png.
app.get('/uploads/:theImageName', function(req, res){
console.log(req.params.theImageName); //returns the imageOfApet.png
var theName = req.params.theImageName; //imageOfApet.png
res.sendFile(__dirname + "/uploads/" + theName); //Sending the user the file
})
I have this code in order to upload single file with node.js, using express and multer:
var express = require("express");
var app = express();
var fs = require("fs");
var multer = require('multer');
var upload = multer({ dest: 'uploads/' });
// Process upload file
app.post('/file_upload', upload.single('single-file'), function(request, response) {
var fileName = request.file.originalname;
var filePath = request.file.path;
var file = __dirname + "/uploads/" + fileName;
fs.readFile(filePath, function(err, data) {
fs.writeFile(file, data, function(err) {
if (err) {
console.log(err);
} else {
responseData = {
'message' : 'File uploaded successfully',
'fileName' : fileName
};
}
response.end(JSON.stringify(responseData));
})
});
});
Here is the HTML file:
<!DOCTYPE html>
<html>
<head>
<title>File Uploading Form</title>
</head>
<body>
<h3>File Upload:</h3>
Select a file to upload: <br />
<form action="http://localhost:8081/file_upload" method="POST"
enctype="multipart/form-data">
<input type="file" name="single-file" size="50" />
<br />
<input type="submit" value="Upload File" />
</form>
</body>
</html>
After running the code, I was able to uploaded file.
But the problem is, I keep getting 2 files uploaded in my "uploads" folder each time. One file with the original name, and one with strange name like 2787ab2db292d90bd2da83a6a6ce1700.
Is that normal? How can I get rid of the other file when upload?
the problem is You're creating new file from already uploaded file.
so solution is to rename uploaded file with temporary name to original name:
var express = require("express");
var app = express();
var fs = require("fs");
var multer = require('multer');
var uploadsFolder = __dirname + '/uploads/'; // defining real upload path
var upload = multer({ dest: uploadsFolder }); // setting path for multer
// Process upload file
app.post('/file_upload', upload.single('single-file'), function(request, response) {
var fileName = request.file.originalname; // original file name
var file = request.file.path; // real file path with temporary name
// renaming real file to it's original name
fs.rename(file, uploadsFolder + fileName, function (err) {
if (err) {
console.log(err);
response.json({success:false, message: err});
return;
}
response.json({success:true, message: 'File uploaded successfully', fileName: fileName});
});
});
or make multer to upload to temporary folder and then copy or move to uploads folder:
install fs extra:
npm install --save fs.extra
and
var express = require("express");
var app = express();
var fs = require('fs.extra'); // extra functionality
var multer = require('multer');
var uploadsFolder = __dirname + '/uploads/'; // defining real upload path
var tempFolder = __dirname + '/tmp/'; // folder for temporary files, must exist
var upload = multer({ dest: tempFolder }); // setting path for multer
// Process upload file
app.post('/file_upload', upload.single('single-file'), function(request, response) {
var fileName = request.file.originalname; // original file name
var file = request.file.path; // real file path with temporary name
// renaming real file to it's original name
fs.move(file, uploadsFolder + fileName, function (err) {
if (err) {
console.log(err);
response.json({success:false, message: err});
return;
}
response.json({success:true, message: 'File uploaded successfully', fileName: fileName});
});
});
Please consider newer answers that have more up-to-date information as things have changed over the years!
Since many new Node.js libraries are quickly being rendered obsolete and there are relatively few examples anyways I want to ask about uploading images using:
Node.js (v0.4.1)
Express (1.0.7)
Mongoose (1.1.0).
How have others done it?
I've found: node-formidable, but I am new to uploading images in general so I want to learn general stuff and ways of doing so using Node.js and Express.
I'll answer my own question for the first time. I found an example straight from the source. Please forgive the poor indentation. I wasn't sure how to indent properly when copying and pasting. The code comes straight from Express multipart/form-data example on GitHub.
// Expose modules in ./support for demo purposes
require.paths.unshift(__dirname + '/../../support');
/**
* Module dependencies.
*/
var express = require('../../lib/express')
, form = require('connect-form');
var app = express.createServer(
// connect-form (http://github.com/visionmedia/connect-form)
// middleware uses the formidable middleware to parse urlencoded
// and multipart form data
form({ keepExtensions: true })
);
app.get('/', function(req, res){
res.send('<form method="post" enctype="multipart/form-data">'
+ '<p>Image: <input type="file" name="image" /></p>'
+ '<p><input type="submit" value="Upload" /></p>'
+ '</form>');
});
app.post('/', function(req, res, next){
// connect-form adds the req.form object
// we can (optionally) define onComplete, passing
// the exception (if any) fields parsed, and files parsed
req.form.complete(function(err, fields, files){
if (err) {
next(err);
} else {
console.log('\nuploaded %s to %s'
, files.image.filename
, files.image.path);
res.redirect('back');
}
});
// We can add listeners for several form
// events such as "progress"
req.form.on('progress', function(bytesReceived, bytesExpected){
var percent = (bytesReceived / bytesExpected * 100) | 0;
process.stdout.write('Uploading: %' + percent + '\r');
});
});
app.listen(3000);
console.log('Express app started on port 3000');
Since you're using express, just add bodyParser:
app.use(express.bodyParser());
then your route automatically has access to the uploaded file(s) in req.files:
app.post('/todo/create', function (req, res) {
// TODO: move and rename the file using req.files.path & .name)
res.send(console.dir(req.files)); // DEBUG: display available fields
});
If you name the input control "todo" like this (in Jade):
form(action="/todo/create", method="POST", enctype="multipart/form-data")
input(type='file', name='todo')
button(type='submit') New
Then the uploaded file is ready by the time you get the path and original filename in 'files.todo':
req.files.todo.path, and
req.files.todo.name
other useful req.files properties:
size (in bytes)
type (e.g., 'image/png')
lastModifiedate
_writeStream.encoding (e.g, 'binary')
You can configure the connect body parser middleware in a configuration block in your main application file:
/** Form Handling */
app.use(express.bodyParser({
uploadDir: '/tmp/uploads',
keepExtensions: true
}))
app.use(express.limit('5mb'));
See, the best thing you can do is to just upload the image to the disk and save the URL in MongoDB. Rest when you retrieve the image again. Just specify the URL, and you will get an image. The code for uploading is as follows.
app.post('/upload', function(req, res) {
// Get the temporary location of the file
var tmp_path = req.files.thumbnail.path;
// Set where the file should actually exists - in this case it is in the "images" directory.
target_path = '/tmp/' + req.files.thumbnail.name;
// Move the file from the temporary location to the intended location
fs.rename(tmp_path, target_path, function(err) {
if (err)
throw err;
// Delete the temporary file, so that the explicitly set temporary upload dir does not get filled with unwanted files.
fs.unlink(tmp_path, function() {
if (err)
throw err;
//
});
});
});
Now save the target path in your MongoDB database.
Again, while retrieving the image, just extract the URL from the MongoDB database, and use it on this method.
fs.readFile(target_path, "binary", function(error, file) {
if(error) {
res.writeHead(500, {"Content-Type": "text/plain"});
res.write(error + "\n");
res.end();
}
else {
res.writeHead(200, {"Content-Type": "image/png"});
res.write(file, "binary");
}
});
Try this code.It will help.
app.get('/photos/new', function(req, res){
res.send('<form method="post" enctype="multipart/form-data">'
+ '<p>Data: <input type="filename" name="filename" /></p>'
+ '<p>file: <input type="file" name="file" /></p>'
+ '<p><input type="submit" value="Upload" /></p>'
+ '</form>');
});
app.post('/photos/new', function(req, res) {
req.form.complete(function(err, fields, files) {
if(err) {
next(err);
} else {
ins = fs.createReadStream(files.photo.path);
ous = fs.createWriteStream(__dirname + '/directory were u want to store image/' + files.photo.filename);
util.pump(ins, ous, function(err) {
if(err) {
next(err);
} else {
res.redirect('/photos');
}
});
//console.log('\nUploaded %s to %s', files.photo.filename, files.photo.path);
//res.send('Uploaded ' + files.photo.filename + ' to ' + files.photo.path);
}
});
});
if (!module.parent) {
app.listen(8000);
console.log("Express server listening on port %d, log on to http://127.0.0.1:8000", app.address().port);
}
You can also use the following to set a path where it saves the file.
req.form.uploadDir = "<path>";
I created an example that uses Express and Multer. It is very simple and avoids all Connect warnings
It might help somebody.
Again if you don't want to use bodyParser, the following works:
var express = require('express');
var http = require('http');
var app = express();
app.use(express.static('./public'));
app.configure(function(){
app.use(express.methodOverride());
app.use(express.multipart({
uploadDir: './uploads',
keepExtensions: true
}));
});
app.use(app.router);
app.get('/upload', function(req, res){
// Render page with upload form
res.render('upload');
});
app.post('/upload', function(req, res){
// Returns json of uploaded file
res.json(req.files);
});
http.createServer(app).listen(3000, function() {
console.log('App started');
});
For Express 3.0, if you want to use the formidable events, you must remove the multipart middleware, so you can create the new instance of it.
To do this:
app.use(express.bodyParser());
Can be written as:
app.use(express.json());
app.use(express.urlencoded());
app.use(express.multipart()); // Remove this line
And now create the form object:
exports.upload = function(req, res) {
var form = new formidable.IncomingForm;
form.keepExtensions = true;
form.uploadDir = 'tmp/';
form.parse(req, function(err, fields, files){
if (err) return res.end('You found error');
// Do something with files.image etc
console.log(files.image);
});
form.on('progress', function(bytesReceived, bytesExpected) {
console.log(bytesReceived + ' ' + bytesExpected);
});
form.on('error', function(err) {
res.writeHead(400, {'content-type': 'text/plain'}); // 400: Bad Request
res.end('error:\n\n'+util.inspect(err));
});
res.end('Done');
return;
};
I have also posted this on my blog, Getting formidable form object in Express 3.0 on upload.
I know that the original question related to specific versions, but it also referred to the "latest" - #JohnAllen 's post is no longer relevant due to Expressjs bodyParser and connect-form
This demonstrates the easy to use in-built bodyParser():
/**
* Module dependencies.
*/
var express = require('express')
var app = express()
app.use(express.bodyParser({ keepExtensions: true, uploadDir: '/home/svn/rest-api/uploaded' }))
app.get('/', function(req, res){
res.send('<form method="post" enctype="multipart/form-data">'
+ '<p>Image: <input type="file" name="image" /></p>'
+ '<p><input type="submit" value="Upload" /></p>'
+ '</form>');
});
app.post('/', function(req, res, next){
res.send('Uploaded: ' + req.files.image.name)
return next()
});
app.listen(3000);
console.log('Express app started on port 3000');
There's my method to multiple upload file:
Nodejs :
router.post('/upload', function(req , res) {
var multiparty = require('multiparty');
var form = new multiparty.Form();
var fs = require('fs');
form.parse(req, function(err, fields, files) {
var imgArray = files.imatges;
for (var i = 0; i < imgArray.length; i++) {
var newPath = './public/uploads/'+fields.imgName+'/';
var singleImg = imgArray[i];
newPath+= singleImg.originalFilename;
readAndWriteFile(singleImg, newPath);
}
res.send("File uploaded to: " + newPath);
});
function readAndWriteFile(singleImg, newPath) {
fs.readFile(singleImg.path , function(err,data) {
fs.writeFile(newPath,data, function(err) {
if (err) console.log('ERRRRRR!! :'+err);
console.log('Fitxer: '+singleImg.originalFilename +' - '+ newPath);
})
})
}
})
Make sure your form has enctype="multipart/form-data"
I hope this gives you a hand ;)
Here's a way to upload your images using the formidable package, which is recommended over bodyParser in later versions of Express. This also includes the ability to resize your images on the fly:
From my website: Uploading and Resizing Images (on the fly) With Node.js and Express.
Here's the gist:
var express = require("express"),
app = express(),
formidable = require('formidable'),
util = require('util')
fs = require('fs-extra'),
qt = require('quickthumb');
// Use quickthumb
app.use(qt.static(__dirname + '/'));
app.post('/upload', function (req, res){
var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files) {
res.writeHead(200, {'content-type': 'text/plain'});
res.write('received upload:\n\n');
res.end(util.inspect({fields: fields, files: files}));
});
form.on('end', function(fields, files) {
/* Temporary location of our uploaded file */
var temp_path = this.openedFiles[0].path;
/* The file name of the uploaded file */
var file_name = this.openedFiles[0].name;
/* Location where we want to copy the uploaded file */
var new_location = 'uploads/';
fs.copy(temp_path, new_location + file_name, function(err) {
if (err) {
console.error(err);
} else {
console.log("success!")
}
});
});
});
// Show the upload form
app.get('/', function (req, res){
res.writeHead(200, {'Content-Type': 'text/html' });
/* Display the file upload form. */
form = '<form action="/upload" enctype="multipart/form-data" method="post">'+ '<input name="title" type="text" />
'+ '<input multiple="multiple" name="upload" type="file" />
'+ '<input type="submit" value="Upload" />'+ '</form>';
res.end(form);
});
app.listen(8080);
NOTE: This requires Image Magick for the quick thumb resizing.
It will become easy to store files after converting in string you just have to convert string in image in your frontend
convert image in to base64 string using this code in your api and also don't forgot to delete file from upload folder
"img": new Buffer.from(fs.readFileSync(req.file.path)).toString("base64")
to delete the file
let resultHandler = function (err) {
if (err) {
console.log("unlink failed", err);
} else {
console.log("file deleted");
}
}
fs.unlink(req.file.path, resultHandler);
at your routes import multer
`multer const multer = require('multer');
const upload = multer({ dest: __dirname + '/uploads/images' });`
Add upload.single('img') in your request
router.post('/fellows-details', authorize([Role.ADMIN, Role.USER]),
upload.single('img'), usersController.fellowsdetails);
OR
If you want save images in localstorage and want save path in database you can try following approach
you have to install first the fs-extra which will create folder. I am creating separate folders by id's if you want to remove it you can remove it. and
to save path of image where it is uploaded add this code in your api or controller you are using to save image and and add it in database with other data
let Id = req.body.id;
let path = `tmp/daily_gasoline_report/${Id}`;
create separate folder for multer like multerHelper.js
const multer = require('multer');
let fs = require('fs-extra');
let storage = multer.diskStorage({
destination: function (req, file, cb) {
let Id = req.body.id;
let path = `tmp/daily_gasoline_report/${Id}`;
fs.mkdirsSync(path);
cb(null, path);
},
filename: function (req, file, cb) {
// console.log(file);
let extArray = file.mimetype.split("/");
let extension = extArray[extArray.length - 1];
cb(null, file.fieldname + '-' + Date.now() + "." + extension);
}
})
let upload = multer({ storage: storage });
let createUserImage = upload.array('images', 100);
let multerHelper = {
createUserImage,
}
module.exports = multerHelper;
In your routes import multerhelper file
const multerHelper = require("../helpers/multer_helper");
router.post(multerHelper. createUserImage , function(req, res, next) {
//Here accessing the body datas.
})