Search code examples
reactjsmongodbmeteor

How to download a file stored as Binary in MongoDB


I am using MeteorJs, MongoDB and React. I want to simply make a module to upload/download files and store them in a MongoDB collection. So far, I can upload the file but I don't know how to download it.

This is the method in server:

Meteor.methods({
  'saveFile': function(one){
      ChivoFiles.insert({data:one.buffer})         
  }   
});

This is the upload in client:

uploadFile(event) {  
    var file = event.target.files[0]; //assuming 1 file only
    if (!file) return;
    var reader = new FileReader(); //create a reader according to HTML5 File API
    reader.onload = function(event){          
      var elBuffer = new Uint8Array(reader.result) // convert to binary
      const one= {buffer: elBuffer}
      Meteor.call('saveFile', one);
    }
    reader.readAsArrayBuffer(file);
}

 <input type="file" id="fileinput" disabled={this.state.inProgress} ref="fileinput" onChange={this.uploadFile}/>

And this is how it look in MongoDB Compass: enter image And this is how it look in MongoDB

I would like to know how I can convert the Mongo document into a downloadable file. Thanks


Solution

  • Problem here is the following:

    the saved data is an EJSON format of binary. What you need to do is, is to create an HTTP endpoint, get the doc and manually link the data to an http route:

    import { WebApp } from 'meteor/webapp'
    
    WebApp.connecthandlers.use('/download', (req, res) => {
      const file = ChivoFiles.findOne(req.query.id)
      const binary = file.data
    
      res.writehead(200, { 
        'Content-disposition': `attachment; filename=${file.name}`
        'Content-type': file.mimetype
      }); // this is why you need to save the name and mime, too
    
    
      const filestream = fs.createReadStream(binary);
      filestream.pipe(res);
    })
    

    You can call this via HTTP GET /download?id=01234567890

    An easier way to manage files

    There is very popular Meteor-Files package, which handles file upload, download, permission etc.

    It's the perfect solution for your use-case.

    You can use it together with external storages (S3 etc.) or local storages (FileSystem, GridFs): https://github.com/veliovgroup/Meteor-Files/blob/master/docs/3rd-party-storage.md

    It also represents your files as documents in a Mongo.Collection, so you can access file information and meta data, without actually downloading the files.

    Downloading files is handled via MyFilesCollection.link(fileDoc._id) which creates a http-based download link for the file, represented by the fileDoc (which itself is created on upload).