A coach in my application can upload an image for his profile, clients, programs and exercise.
After the file has been upload, the nodejs server rename it. Then the nodejs server needs to insert / update the image name on the db, according to the form that sends the image (registration, edit user, add client, edit client and so on...).
Therefore I want to send additional data / parameters to the nodejs function.
HTML:
<form name="userUpdateForm" action="/university/uploadImage" method="post" enctype="multipart/form-data" id="editUserForm">
<label>Replace Logo Image</label></br>
<input id="uploadFile" name="filetoupload" type="file">
<input type="submit">
</form>
Node:
router.post('/uploadImage', function (req,res,next) {
var newpath = "";
var form = new formidable.IncomingForm();
form.parse(req, function (err, fields, files) {
var oldpath = files.filetoupload.path;
var time = new Date();
var newImageName = time.getHours() + "-" + time.getMinutes() + "-" + time.getSeconds() + "-" + files.filetoupload.name;
newpath = './uploaded/' + newImageName;
//sendToDbImageName(newImageName);
fs.readFile(oldpath, function (err, data) {
if (err) throw err;
console.log('File read!');
// Write the file
fs.writeFile(newpath, data, function (err) {
if (err) throw err;
console.log('File uploaded and moved!');
console.log('File written!');
res.redirect(url + '?uid=' + globalUid + '#/editUser');
});
// Delete the file
fs.unlink(oldpath, function (err) {
if (err) throw err;
console.log('File deleted!');
});
});
});
});
Update:
This is how I solved that:
One function that's takes an image from different forms (coach, client, program, exercise), generate unique file name, and insert / update the database.
Don't repeat; check,
Don't go twice to the server; check,
Prevent redirect after file was upload; check.
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, __dirname + '/../uploaded')
},
filename: function (req, file, cb) {
var time = new Date();
cb(null, time.getHours() + "-" + time.getMinutes() + "-" +
time.getSeconds() + "-" + file.originalname) //Appending extension
}
})
var upload = multer({ storage: storage });
router.post('/uploadImage', upload.single('avatar'), function (req, res, next) {
var formName = req.body.formName;
switch (formName) {
case "editUser":
var sql = "UPDATE coachdirectory SET logo = '" + req.file.filename + "' WHERE uid = '" + req.body.uid + "'";
con.query(sql, function (err, result) {
if (err) throw err;
console.log(result.affectedRows + " record(s) updated");
});
res.redirect(url + '/?uid=' + req.body.uid + '#/yourClients');
break;
case "registerUser:
other business logic
break;
}
});
The best practice is using Multer package developed by ExpressJS. Server handling file upload is really difficult, so they created multer which is basically built on top of busboy. There are some edge cases you also need to handle when you do it by scratch. No need of reinventing the wheel. Better use Multer as you can pass normal formal data in multipart itself. Multer will attach those to req.body by default.
In Multer, you have the flexibility to rename the file before saving it the database itself or keep the original filename.
Related
I have a typical client/server application where i can send images to the server and i need that image on the client with diferent sizes.
So at the moment i am using Picasso with android to load the image, and with nodeJS i am serving the images as static files, since they are saved in the folder where the static files are.
My question is: is there a way to increase the speed sending this static files(just the images), or can i decrease the size of them using the code that i currently have for the static file?
app.use(express.static(path.join(__dirname, 'public')));
at the moment i receive the image from the client as base64 and on the server i convert it to a bitmap like this:
var bitmap = new Buffer(req.body.base64, 'base64');
and store that bitmap on the public folder that i use as a static folder, i dont store the image directly on the database since that is bad practice, i just save the path and everytime i want to retrive the image i know inside the static folder where it is.
So everytime on my client that i want to retrive a foto i just need to know what is the static path, nothing more.
For a better understanding i leave here the code for 1 of my controllers where i save the photo.
controller
sendPicture: function (req, res, next) {
var plant = null
if (req.params.id != 0) {
plant = req.params.id;
}
var bitmap = new Buffer(req.body.base64, 'base64');
var lat = req.body.lat;
var lon = req.body.lon;
var alt = req.body.alt;
var date = req.body.date;
var flowerName;
var pathId = shortid.generate();
var userId = req.userId;
if (plant != null) {
Plant.findOne({
where: { id: req.params.id }
}).then(function (plant) {
if (!plant) {
return 'not found';
}
flowerName = plant.specie;
}).then(function () {
var pathToSave = __dirname + "/../public/images/" + flowerName + "/" + pathId + req.params.id + "-" + userId + ".jpg";
var path = "images/" + flowerName + "/" + pathId + req.params.id + "-" + userId + ".jpg"
fsPath.writeFile(pathToSave, bitmap, function (err) {
if (err) {
console.log(err.stack);
return err;
}
Foto.create({
image: path,
userId: userId,
plantId: req.params.id,
lat: req.body.lat,
lon: req.body.lon,
alt: req.body.alt,
date: date,
}).then(function () {
return res.status(200).json({ message: "foto created" });
}).catch(function (err) {
console.log(err.stack);
})
});
});
}
I have a root directory say "A" inside this directory i am having lots of directories say "1","2","3","4","5"........ and in all these subdirectories i have single file called cucumber.json. All i want to do is read the cucumber.json file and get the accumulated result. How can i achieve this using node js.
In the below screen shot my root directory is "cucumber" and inside that i have lot of sub directories. All these sub directories contains a single file named cucumber.json.
Are there any dedicated node package which can make my work easy.
Let me know if any further info is required.
Hi there please try the following (javascript):
// Require filesystem package for IO operations
var fs = require('fs');
// Put the path you are looking for here
var path = "d:\\nodef";
//Call the function defined below
recursiveloop(path, function(err,result){
/* begin processing of each result */
// For each file in the array
for(i=0;i<result.length;i++)
{
//Write the name of the file
console.log('Processing: ' + result[i]);
//Read the file
fs.readFile(result[i], 'utf8', function(err, data){
//If there is an error notify to the console
if(err) console.log('Error: ' + err);
//Parse the json object
var obj = JSON.parse(data);
//Print out contents
console.log('Name: ' + obj.name);
console.log('Position: ' + obj.position);
})
}
});
// Asynchronous function to read folders and files recursively
function recursiveloop(dir, done)
{
var results = [];
fs.readdir(dir, function(err, list){
if (err) return done(err);
var i = 0;
(function next() {
var file = list[i++];
if (!file) return done(null, results);
file = dir + '/' + file;
fs.stat(file, function(err, stat) {
if (stat && stat.isDirectory()) {
recursiveloop(file, function(err, res) {
results = results.concat(res);
next();
});
} else {
results.push(file);
next();
}
});
})();
});
}
Trying to allow users to upload image files to the Node.js server in a MEAN Stack application. I am using ng-file-upload for the client side angular directive. That seems to be working good enough. I run into an error when I pass the image to the server.
I use an API route to handle the work on the server side. The server will be responsible for saving the file to disk with node-multiparty module. It seems to hit route but when it tries to emit a close event I get the error. throw new Error('"name" and "value" are required for setHeader().'
The file I want is in my temp folder but it doesn't get saved to the target directory on my server plus I get the header error after the file should have been saved. So I need to stop the error and save the file with fs.rename() to the target image directory.
Here is the code that is breaking.
file api.js
// router to save images
router.route('/img/upload')
.post(function (req, res) {
console.log("image upload hits the router")
var options = {};
var count = 0;
var form = new multiparty.Form(options);
//save file to disk
form.on('file', function (name, file) {
var uploadDirectory = 'img/user/profile/';
var oldPath = file.path;
var newPath = uploadDirectory + file.originalFilename;
fs.rename(oldPath, newPath, function (err) {
if (err) throw err;
console.log('renamed complete');
});
});
// Close emitted after form parsed
form.on('close', function () {
console.log('Upload completed!');
res.setHeader('text/plain'); // Here is the line that gives an error.
res.end('Received ' + count + ' files');
});
// Parse req
form.parse(req);
});
So this is what I got to work for me
The actual line that gave me an error was setHeaders. It appears I needed to put the name and value as strings separated by a comma. This works perfectly for me now. I hope it saves everyone time coding.
// post
.post(function (req, res) {
var options = {};
var count = 0;
var form = new multiparty.Form(options);
form.on('error', function (err) {
console.log('Error parsing form: ' + err.stack);
});
//save file to disk
form.on('file', function (name, file) {
var uploadDirectory = '/img/user/profile/';
var oldPath = file.path;
var newPath = uploadDirectory + file.originalFilename;
fs.rename(oldPath, newPath, function (err) {
if (err) throw err;
console.log('renamed complete');
});
});
// Close emitted after form parsed
form.on('close', function () {
console.log('Upload completed!');
res.setHeader('Content-Type', 'text/plain');
res.end('Received ' + count + ' files');
});
// Parse req
form.parse(req);
});
I am just trying to upload and save images in my public/images folder, I am getting the details of file by req.files, after that I am getting this type of Error: EXDEV, rename 'c:\Users\abdul\AppData\Local\Temp\3348-qiy7kl.jpg'
here is my stuff
app.post('/upload',function(req,res){
var tmp_path = req.files.file.path;
var target_path = './public/images/' + req.files.file.originalFilename;
fs.rename(tmp_path, target_path, function(err) {
if (err) throw err;
fs.unlink(tmp_path, function() {
if (err) throw err;
res.send('File uploaded to: ' + target_path + ' - ' + req.files.file.size + ' bytes');
});
});
})
};
Can any body give any suggestion or give me any reference so that I can handle it?
Try this one
console.log("File Name " + req.files.file.name);
console.log("File Path " + req.files.file.path);
fs.readFile(req.files.file.path, function (err, data) {
var newPath = "public/images/" + req.files.file.originalFilename;
console.log(newPath);
/// write file to uploads/fullsize folder
fs.writeFile(newPath, data, function (err) {
/// let's see it
});
I have the following code (trimmed, assume all the closing stuff is there), which dies deep down inside GridFS:
var Grid = require('mongodb').Grid;
var mongoose = require('mongoose');
var db = mongoose.connect('mongodb://localhost:27017/ksnap');
router.route('/').post(function(req, res) {
var post = new Post();
var busboy = new Busboy({ headers: req.headers });
req.pipe(busboy);
busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {
console.log('File [' + fieldname + ']: filename: ' + filename + ', encoding: ' + encoding + ', mimetype: ' + mimetype);
if (fieldname != 'img') { return; }
var bufs = [];
file.on('data', function(data) {
console.log('File [' + fieldname + '] got ' + data.length + ' bytes');
bufs.push(data);
}); // busboy file on data
file.on('end', function() {
console.log('File [' + fieldname + '] Finished');
var buf = Buffer.concat(bufs);
var grid = new Grid(db, 'fs');
grid.put(buf, {metadata:{category:'image'}, content_type: 'image'}, function(err, result) {
if (err) { console.log(err); } else { console.log(result); }
});
Stack trace:
/opt/ksnap-server/node_modules/mongodb/lib/mongodb/gridfs/gridstore.js:1552
} else if(self.safe.w != null || typeof self.safe.j == 'boolean' || typeof s
^
TypeError: Cannot read property 'w' of undefined
at _getWriteConcern (/opt/ksnap-server/node_modules/mongodb/lib/mongodb/gridfs/gridstore.js:1552:22)
at Stream.GridStore (/opt/ksnap-server/node_modules/mongodb/lib/mongodb/gridfs/gridstore.js:100:23)
at Grid.put (/opt/ksnap-server/node_modules/mongodb/lib/mongodb/gridfs/grid.js:52:19)
at FileStream.<anonymous> (/opt/ksnap-server/server.js:83:13)
at FileStream.emit (events.js:117:20)
at _stream_readable.js:943:16
at process._tickCallback (node.js:419:13)
Busboy returns a stream which I put into a buffer, so far so good. This works fine, I've tested it. But when I try to grid.put() the buffer, it dies as above. I've tried to trace it, but I'm having trouble. As far as I can tell, the all the options get eaten in grid.js, so by the time they get passed down to gridstore.js it's just an empty object. Mongoose just doesn't set this, I guess.
I was able to get past this error by manually setting db.safe = {w: 1}; after opening the connection, however when I did the grid.put() it just stuck there. Swapping out mongoose for a regular mongodb connection worked, so I guess currently mongoose just doesn't work with GridFS.
I was finally able to get everything (apparently) working by adding the streamifier and gridfs-stream modules, and the following mongo setup:
var streamifier = require('streamifier');
var Grid = require('gridfs-stream');
mongoose.connect('mongodb://localhost:27017/ksnap');
Then later, when I'm ready to save the file to GridFS:
var gfs = new Grid(mongoose.connection.db, mongoose.mongo);
var writestream = gfs.createWriteStream({
mode: 'w',
filename: post.id,
content_type: 'image/jpeg'
});
streamifier.createReadStream(buffer).pipe(writestream);
writestream.on('close', function (file) {
console.log("saved 300px as "+file.filename);
});
And save the post document itself to MongoDB:
post.save(function(err) {
if (err) { res.send(err); }
console.log('saved post '+post.id);
res.send(post);
});
This was the combination of options that worked for me. One of the keys was using mongoose.connect(), not mongoose.createConnection(), which would let me save the files, but not the documents.
I know this has been a while - I saw the same issue - make sure your mongoose session is connected to the DB - ie
mongoose.connection.once("connected", function () {...} has been called, then load the require files and files. This ensures the db object in the connection is bound to an existing mongo session. If you find the mongoose.connection.db is null and mongoose.connection is NOT null then you will have initialized your grid stream with an uninitialized mongodb connection.