multer: dynamic destination path

Zeokav picture Zeokav · Jan 2, 2017 · Viewed 10.2k times · Source

I am writing a node application and I was looking for something to upload files on the server. I could get files to upload when there was only one static directory. But I need to make directories per user and then upload files to those, according to the user that's logged in. I looked stuff up but everything that I try ends in an Error: ENOENT: no such file or directory, open ... error. What I am trying to do currently is this -

let storage = multer.diskStorage({
  destination: function(req, file, cb) {
    let dest = path.join(__dirname, './documents', 'somenameigetfromtheuser');
    let stat = null;
    try {
      stat = fs.statSync(dest);
    }
    catch (err) {
      fs.mkdirSync(dest);
    }
    if (stat && !stat.isDirectory()) {
      throw new Error('Directory cannot be created');
    } 
    cb(null, dest);
  }
});

let upload = multer({
  storage: storage,
  dest: 'documents/'
});

app.post('/testUpload', upload.single('testfile'), (req, res) => {
  res.json({
    test: 'test'
  })
});

There is a similar question that has been answered but it doesn't work that way for me because I want the directory name from the request object.

When I remove the storage property in my multer initialization, the files are stored in the documents directory with a random name. I want the file to have its original name and I want it to be stored in a directory where I get the name of the directory from the req object.
Help a brother out, thanks!

Answer

Łukasz picture Łukasz · Jan 15, 2017

edited

See https://github.com/expressjs/multer#diskstorage

Note that req.body might not have been fully populated yet. It depends on the order that the client transmits fields and files to the server.

Due to that, first write file in temp directory, read directory name from req and move file:

fs = require('fs-extra'); //npm install fs.extra
...

var storage = multer.diskStorage({ 
    destination: function (req, file, cb) {
        cb(null, '../tempDir/')
    },
    filename: function (req, file, cb) {
        cb(null, file.originalname)
    }
});

var upload = multer({ 
    storage: storage
}).single('file');

upload(req, res, function (err) {
    if (err) {
        res.json({});
        return;
    }

    var dir = JSON.parse(req.body.data).directory;
    var filename = req.file.filename;

    fs.move('../tempDir/' + fileName, '../tempDir/' + dir + '/' + fileName, function (err) {
        if (err) {
            return console.error(err);
        }

        res.json({});
    });

});