1

I have a utility module that creates an instance of a multer-gridfs storage engine for uploading files to my Mongo database. I use this module inside of any API route that requires the need to upload files.

I need to be able to update the metadata property value with a unique identifier. More than likely this will be the mongoose _id of the user uploading the file, but for now I am not concerned with that aspect of it. I really just want to know if I can change the metadata property dynamically.

Here is the storage engine gridFs_upload_engine.js:

const mongoose = require('mongoose');
const path = require('path');
const crypto = require('crypto');
const multer = require('multer');
const GridFsStorage = require('multer-gridfs-storage');
const Grid = require('gridfs-stream');

//Init Upload Engine
let gfs;
//Global instance of the DB connection
const database = mongoose.connection;
const mongoDb = process.env.MONGODB_URI || process.env.MLAB_URL;

database.once('open', () => {
  //Init Stream
  gfs = Grid(database.db, mongoose.mongo);
  gfs.collection('uploads');
});

//Create Storage Engine
const storage = new GridFsStorage({
  url: mongoDb,
  file: (res, file) => {
    return new Promise((resolve, reject) => {
      crypto.randomBytes(16, (err, buf) => {
        if (err) {
          return reject(err);
        }
        const filename = buf.toString('hex') + path.extname(file.originalname);
        const fileInfo = {
          filename: filename,
          bucketName: 'uploads',
          metadata: 'NEED TO UPDATE THIS'
        };
        resolve(fileInfo);
      });
    });
  }
});

const uploadEngine = multer({ storage });

module.exports = {
  uploadEngine,
  gfs
};

Above you can see the metadata property that I need to be able to dynamically change with some undetermined unique identifier. Is it possible to do that with an exported file?

Here is how I am utilizing it inside of an API route:

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

//Controllers
const upload_controller = require('../../controllers/uploader');

//Utilities
const upload = require('../../utils/gridFs_upload_engine');

const { uploadEngine } = upload;

//Upload Single File
router.post(
  '/single',
  uploadEngine.single('file'),
  upload_controller.upload_single_file
);

//Upload Multiple Files
//Max file uploads at once set to 30
router.post(
  '/multiple',
  uploadEngine.array('file', 30),
  upload_controller.upload_multiple_files
);

module.exports = router;

I pass the uploadEngine into the API route here, so that the route controller can use it, and that works with no issue. I am just having quite a time trying to figure out how to update metatdata dynamically and I am leaning towards my current implementation not allowing for that.

chazsolo
  • 7,873
  • 1
  • 20
  • 44
maison.m
  • 813
  • 2
  • 19
  • 34
  • Where does `metadata` come from? – Jonas Wilms Apr 10 '19 at 17:48
  • metadata is a property provided by multer-gridfs-storage. That node package documentation can be found here: https://www.npmjs.com/package/multer-gridfs-storage – maison.m Apr 10 '19 at 23:31
  • By default it is set to null. It’s reserved for attaching any other data to the file name that might be helpful. In my specific case, the metadata property will be used to store a mongoose _id of the user who uploaded the file. – maison.m Apr 10 '19 at 23:32

2 Answers2

1

I don't know much about node and have now idea what multer-gridfs is but I can answer How can I pass options into an imported module?

You can export an function that returns another function. And you would import it like

const configFunction = require('nameoffile')
// this returns a functions with the config you want
const doSomethingDependingOnTheConfig = configFunction({...someConfig}) 

And in the file you are importing you would have a function returning another function like

const configFunction = ({...someConfig}) => (your, func) => {

    // do what you want deppending on the config

}

module.exports = configFunction

I know this doesn't answer your question the way you want, but answer you question title and I hope this give you a better understanding of how to do what you want to do.

If this doesn't help, just let me know.

Vencovsky
  • 28,550
  • 17
  • 109
  • 176
1

You would need to pass a parameter to the module gridFs_upload_engine.js and do the magic there.

An example could be:

In gridFs_upload_engine.js file:

function uploadEngine (id, file) {
  // update what you want
}

module.exports = {
  ...
  uploadEngine: uploadEngine
}

In your router:

const upload = require('../../utils/gridFs_upload_engine')
...

router.post('/single/:id', function(req, res, next) {
  ...
  upload.uploadEngine(req.params.id, file)
  next()

}, upload_controller.upload_single_file)

In other words, when you are exposing gfs and uploadEngine inside your module, you could instead expose a function that would receive the arguments needed to perform the upload.

Patrick
  • 140
  • 6