Load image from skipper-gridfs to Sails.js

I am uploading images to server using gridfs in sails.js app. My download codes are as follows

upload: function  (req, res) {
        req.file('avatar')
            .upload({
                adapter: require('skipper-gridfs'),
                uri: 'mongodb://localhost:27017/dbname.images'
            }, function whenDone(err, uploadedFiles) {
                if (err) return res.negotiate(err);
                else return res.ok({
                    files: uploadedFiles,
                    textParams: req.params.all()
                });
            });
    }

      

I am getting the following answer from this ...

{
    "files": [
        {
            "fd": "2d8910a0-8ca2-4df1-9930-6ddd721a0416.jpg",
            "size": 172883,
            "type": "image/jpeg",
            "filename": "Photo on 12-20-14 at 9.53 PM.jpg",
            "status": "bufferingOrWriting",
            "field": "avatar",
            "extra": {
                "fileId": "54aee6ced4a0e88f0dc9025f",
                "fd": "2d8910a0-8ca2-4df1-9930-6ddd721a0416.jpg",
                "dirname": "."
            }
        }
    ],
    "textParams": {}
}

      

My question is, if I need to download the downloaded file above, what should I do? I got the following code online to download a task, but it doesn't make a lot of sense to me. Basically, I want to load the url of the uploaded image in order to use that url in the mobile app to display the image.

var blobAdapter = require('skipper-gridfs')({
            uri: 'mongodb://localhost:27017/dbname.images'
        });
        blobAdapter.read(filename, callback);

      

Can anyone help me with this? Thanks in advance.

+3


source to share


2 answers


After some research, I was finally able to solve the problem. I get the field fd

in the response after uploading the file and save it for later use. I went into codes skipper-gridfs

and found a method 'read'

that takes this value and returns the required file. So, I just pulled this file out of mongo by this method and posted as an answer. This is a working file.

download: function (req, res) {
        var blobAdapter = require('skipper-gridfs')({
            uri: 'mongodb://localhost:27017/mydbname.images'
        });

        var fd = req.param('fd'); // value of fd comes here from get request
        blobAdapter.read(fd, function(error , file) {
            if(error) {
                res.json(error);
            } else {
                res.contentType('image/png');
                res.send(new Buffer(file));
            }
        });
    }

      



I hope this helps someone like me in the future :)

+9


source


To add to Ayon's excellent answer above, here's a version of the same code that showcases streams, stored file metadata, dynamic content type, and a couple of other related comments:

download: function (req, res) {

  if (!_.isString(req.param('fileId') && !_.isNumber(req.param('fileId')){
    return res.badRequest('`fileId` should be provided as a string/number (depending on whether this is Mongo or MySQL, if you\'ve customized the primary key, etc.).');
  }

  // Look up file metadata
  UploadedFile.findOne({ id: req.param('fileId') })
  .exec(function (err, fileRecord) {
    if (err) { return res.serverError(err); }
    if (!fileRecord) { return res.notFound(); }

    // Get configured blob adapter instance.
    var blobAdapterOpts = _.omit(sails.config.fileUploads, 'adapter');
    var configuredBlobAdapter = sails.config.fileUploads.adapter(blobAdapterOpts);

    // Now locate the actual raw contents of the file using the
    // `fd` that we saved elsewhere (i.e. when uploading), and then
    // use the blob adapter to open up a stream of bytes (the file's
    // contents) and pipe that down as the HTTP response body.  
    // (like skipping a rock across the surface of a pond)
    var fileStream = configuredBlobAdapter.read(fileRecord.fd);
    fileStream.on('error', function (err){
      return res.serverError(err);
    });

    // Along the way, set the content-type for the response based on
    // whatever we saved when this file was originally uploaded.
    // 
    // (You could do the same thing for the filename, assuming this
    // file download is the "save as" kind, as determined by the
    // content-disposition header.)
    res.contentType(fileRecord.contentType);

    // Pipe the stream of file data through as our HTTP response body.
    // (like skipping a rock on the surface of a pond)
    return fileStream.pipe(res);

  });

}

      

Why flow?

This streaming approach saves us from downloading the entire file in memory on our server (which can be a problem when dealing with large files or with many simultaneous downloads)

Error handler

Since we are dealing with a raw Node stream / emitter in the user-space code here, we must make sure to attach an "error" event handler before doing anything - just in case. (This prevents any unexpected thread errors if the process crashes.)



"open" vs. "save file as"

You can use the request parameter as a flag to determine how to set the title of the content - and therefore the user's browser / device / native application should "open" or "save as" the file.

Custom configuration

This example demonstrates setting up some custom configuration. for example in config / custom.js, you can put: module.exports.custom = {fileUploads: {adapter: require ('skipper-fs'), uri: 'mongodb: // localhost: 27017 / mydbname.images'}, };

How about action2?

If you are using actions2 (available in Sails v1.x and above), you can accomplish the same as res.pipe()

~~ and the associated error handling ~~ by simply streaming directly to exits.success()

. ( EDIT: Actually, I was wrong about the second part of this question - just verified , which still has to handle it on .on('error',...)

its own.) Also, you still have to set the content-type response header; those. env.res.contentType(fileRecord.contentType)

...

+1


source







All Articles