node.jsmongodbexpressmulter-gridfs-storage

How to download and not stream files that i uploaded into MongoDb with node.js, express, mongodb and GridFSBucket?


upload & download functions

My functions for uploading files and downloading files looke like this. The uploadFiles functions works perfectly and do what it should do.

The download doesn't do what I want. It load's the images and stream's them. What i want is, that it download's the file from the database to the device. Is there any possiblity to do that with GridFSBucket, or do I need something else?

const uploadFiles = async(req, res) => {
            try {
                await upload(req, res);
                console.log(req.file);
                if (req.file == undefined) {
                    return res.send({
                        message: "You must select a file.",
                    });
                }
                return res.send({
                    message: "File has been uploaded.",
                });
            } catch (error) {
                console.log(error);
                return res.send({
                    message: "Error when trying upload image: ${error}",
                });
            }
        };
        
        const download = async(req, res) => {
            try {
                await mongoClient.connect();
                const database = mongoClient.db(dbConfig.database);
                const bucket = new GridFSBucket(database, {
                    bucketName: dbConfig.imgBucket,
                });
        
        
                let downloadStream = bucket.openDownloadStreamByName(req.params.name)
                downloadStream.pipe(fs.createWriteStream('./' + req.params.name)).
                on('error', function(error) {
                    console.log("error" + error);
                    res.status(404).json({
                        msg: error.message
                    });
                }).
                on('finish', function() {
                    console.log('done!');
                    res.send('Downloaded successfully!')
                });
                downloadStream.on("data", function(data) {
                    return res.status(200).write(data);
                });
                downloadStream.on("error", function(err) {
                    return res.status(404).send({ message: "Cannot download the Image!" });
                });
                downloadStream.on("end", () => {
                    return res.end();
                });
            } catch (error) {
                return res.status(500).send({
                    message: error.message,
                });
            }
        };

middleware for uploading and store images

const util = require("util");
const multer = require("multer");
const { GridFsStorage } = require("multer-gridfs-storage");
const dbConfig = require("../config/db.config");


var storage = new GridFsStorage({
    url: dbConfig.url,
    options: { useNewUrlParser: true, useUnifiedTopology: true },
    file: (req, file) => {
        const match = ["image/png", "image/jpeg"];
        if (match.indexOf(file.mimetype) === -1) {
            const filename = `${Date.now()}-wolpert-${file.originalname}`;
            return filename;
        }
        return {
            bucketName: dbConfig.imgBucket,
            filename: `${Date.now()}-wolpert-${file.originalname}`
        };
    }
});
var uploadFiles = multer({ storage: storage }).single("file");
var uploadFilesMiddleware = util.promisify(uploadFiles);
module.exports = uploadFilesMiddleware;

routes

const express = require("express");
const router = express.Router();

const uploadController = require("../controller/upload");

const fileRoutes = express.Router({ mergeParams: true });

fileRoutes.route('/upload')
    .post(async(req, res) => {
        await uploadController.uploadFiles(req, res);
    });

fileRoutes.route('/files/:name')
    .get(async(req, res) => {
        await uploadController.download(req, res);
    });

Solution

  • Downloading means streaming the file to the HTTP response, after setting a Content-Disposition header that instructs the browser to download it (rather than display it inline).

    try {
      await mongoClient.connect();
      const database = mongoClient.db(dbConfig.database);
      const bucket = new GridFSBucket(database, {
        bucketName: dbConfig.imgBucket,
      });
      let downloadStream = bucket.openDownloadStreamByName(req.params.name);
      res.set("Content-Disposition", "attachment");
      downloadStream.pipe(res);
    } catch(error) {...