Search code examples
javascriptmongodbmultergridfsmulter-gridfs-storage

Small images (<4MB) in MongoDB, should I use gridFS?


Rather simple question and request here, but haven't been able to find a firm answer yet. I am new to multer, Node, and MongoDB and it's been a bigger struggle than I expected.

I want to store small JPEGs in MongoDB, probably not more 4 MB each. I understand that BSON can be up to < 16 MB, and if larger, must be handled by gridfs.

These images would just be profile photos for each _id I have in a collection. So far, I have been able to upload files locally using just multer. Now I am trying to figure out how to get these images in MongoDB and in the correct way.

Do I need gridfs for such small images? What would be my best plan to execute this?

I am picturing doing an upsert of the file to the database but wonder if this will just upload the filename and not the image itself? How would I change my "schema" to accommodate this? If you have an idea of how to change my upsert below (vs going into gridFS), that would be ideal. Here is the code.

Database update:

const updatePlace = async (place) => {
  const database = await connect();
  return database.collection('place').findOneAndUpdate(
    { _id: new ObjectID(place._id) },
    {
      $set: {
        name: place.name,
        category: place.category,
        city: place.city,
        state: place.state,
        country: place.country,
        image: { filename: place.image, mime: 'image/jpeg' },
      },
    },
    { upsert: true, returnOriginal: false }
  );
};

The storage and upload:

const multer = require('multer');

const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, './public/uploads');
  },
  filename: function (req, file, cb) {
    cb(null, Date.now() + '_' + file.originalname);
  },
});
const upload = multer({ storage: storage });

Mongo DB item as it is now:

{
  "_id": {
    "$oid": "5fbc37c4fc13ae680b00001e"
  },
  "name": "Petronas Towers",
  "category": "activity",
  "city": "Kuala Lumpur",
  "state": "Kuala Lumpur",
  "country": "Malaysia",
  "image": {
    "filename": "petronas.jpg",
    "mime": "image/jpeg"
  }
}

Solution

  • GridFS is not a bad choice. You get:

    • Automatic index creation by the driver, hence efficient retrieval
    • Flexibility if your images grow beyond 16 mb
    • Separate metadata and content storage

    You can alternatively use the binary type and store image data directly in fields. This will have less overhead but:

    • You should either still store metadata separate for content or benchmark that solution vs one where the content is inline in the documents (because skipping over content bytes can be slow when you just need metadata)
    • You would need to handle metadata yourself