3

Framework: node.js/express.js/busboy/gridfs-stream(mongodb)

I am using busboy to upload files and then use gridfs-stream to store files in mongodb gridfs.

                req.pipe(req.busboy);
                req.busboy.on('file', function (bus_fieldname, bus_file, bus_filename) {

                var writestream = gfs.createWriteStream({
                    filename: bus_filename,
                });

                bus_file.pipe(writestream);

                writestream.on('close', function (file) {
                    res.redirect('/xxxxx/');
                });
            });

Download is simple: Use gridfs-stream's createReadStream I read the contents from mongodb and then use the following code to send it to browser.

            gfs.findOne({_id: attachmentid}, function (err, file) {
            if (err || !file){
                res.send(404);
            }else{
                var fileName = file.filename;
                var readstream = gfs.createReadStream({_id: attachmentid});
                var buffer = "";
                readstream.on("data", function (chunk) {
                    buffer += chunk;
                });

                // dump contents to buffer
                readstream.on("end", function () {
                    res.set("Content-Disposition","attachment; filename=" + fileName);
                    res.send(buffer);
                });

            }

Problem: When I upload a 90kb pdf file, it uploads fine. I see the size is correct in mongodb. But when I download, the file size of the downloaded file is about 165kb. There is a mismatch. This does not happen with text files. Sure its something to do with data type.

can anyone please help?

user3658423
  • 1,904
  • 5
  • 29
  • 49

2 Answers2

3

Pipe the gfs read stream to the response directly. This is what works for me

res.set("Content-Disposition","attachment; filename=" + fileName);
var readstream = gfs.createReadStream({_id: attachmentid});
readstream.pipe(res);
Sasikanth Bharadwaj
  • 1,457
  • 1
  • 11
  • 11
1

Like Sasikanth said you can fix the problem with piping and that's the best approach.

But if you are wondering what's wrong with your current approach, then I suggest to read the Buffer documentation.You are naming your variable as buffer but assigning string.

Then in your data callback you are adding string with Buffer. When you do that the chunk buffer is converted to string using it's toString() method. So your binary data is converted to utf8 encoded string and here it goes wrong. Since utf8 is multi-byte encoding the output size becomes large(I don't know the exact mechanism of this conversion).

So the right way to do is to keep it in buffers:

var buffers = [];
readstream.on("data", function (chunk) {
    buffers.push(chunk)
});


readstream.on("end", function () {
    res.set("Content-Disposition","attachment; filename=" + fileName);
    res.send(Buffer.concat(buffers));
});
hassansin
  • 16,918
  • 3
  • 43
  • 49