Search code examples
javascriptfileexpressmultergridfs-stream

GridFS find file by _id download with the name of the file


I want to post a file in express/mongodb with multer and gridfs.

This file gets linked in the frontend with an and if I click on it I want to display the realname of the file though, for example "example.pdf" and not :id.pdf. Right now posting works completely fine I also can save the original filename, but when getting the file by clicking on the link, the filename isn't the original anymore. Even if I try to set it before.

Here are my two routines for get and post:

var router = require('express').Router();
var mongoose = require('mongoose');
var conn = mongoose.connection;
var Grid = require('gridfs-stream');
Grid.mongo = mongoose.mongo;
var gfs = Grid(conn.db);
var fs = require('fs');

router.post('/', function(req, res) {
  var dirname = require('path').dirname(__dirname);
  var filename = req.file.filename;
  var path = req.file.path;

  var type = req.file.mimetype;
  var read_stream =  fs.createReadStream(dirname + '/' + path);

  var writestream = gfs.createWriteStream({
      _id:  filename,
     'filename': req.file.originalname,
     mode: 'w',
     content_type: type
  });
  read_stream.pipe(writestream);

  writestream.on('close', function (file) {
     res.status(200).json({'filename': filename});
   });
});

router.get('/:id',function(req , res) {
  var file_id = req.params.id;

  gfs.files.find({_id: file_id}).toArray(function (err, files) {
    if (err) {
      res.json(err);
    }
    if (files.length > 0) {
      var mime = files[0].contentType;
      var filename = files[0].filename;
      res.set('Content-Type', mime);
      res.set('originalname', filename);
      var read_stream = gfs.createReadStream({_id: file_id});
      read_stream.pipe(res);
    } else {
      res.json('File Not Found');
    }
  });
});

module.exports = router;


Solution

  • I managed to solve my problem, to get the correct name of the file I had to set something in the response, this question on stackoverflow explains it further:

    related question

    I came up then change my code a little to have it like this, here is the improved code:

    var router = require('express').Router();
    var mongoose = require('mongoose');
    var conn = mongoose.connection;
    var Grid = require('gridfs-stream');
    Grid.mongo = mongoose.mongo;
    var gfs = Grid(conn.db);
    var fs = require('fs');
    
    router.post('/', function(req, res) {
      var dirname = require('path').dirname(__dirname);
      var filename = req.file.filename;
      var path = req.file.path;
      var type = req.file.mimetype;
      var read_stream =  fs.createReadStream(dirname + '/' + path);
    
      var writestream = gfs.createWriteStream({
          _id:  filename,
        'filename': req.file.originalname,
         mode: 'w',
         content_type: type
      });
      read_stream.pipe(writestream);
    
      writestream.on('close', function (file) {
         res.status(200).json({'filename': filename});
       });
    });
    
    router.get('/:id',function(req , res) {
      var file_id = req.params.id;
    
      gfs.files.find({_id: file_id}).toArray(function (err, files) {
        if (err) {
          res.json(err);
        }
        if (files.length > 0) {
          var mime = files[0].contentType;
          var filename = files[0].filename;
          res.set('Content-Type', mime);
          res.set('Content-Disposition', "inline; filename=" + filename);
          var read_stream = gfs.createReadStream({_id: file_id});
          read_stream.pipe(res);
        } else {
          res.json('File Not Found');
        }
      });
    });
    
    module.exports = router;

    I hope this provides some help to the ones who also get stuck because of the same reason and I want to thank the ones who read through the question before.