Search code examples
node.jsmongodbmultergridfssharp

How to resize and image before saving it with gridfs?


i'm a beginner with mongoDB and gridfs. I have a code which save in the database an incoming image. But I'd like to resize the image before saving it. It tried to use sharp, but I don't really understand how it works.

I tried the following code, but it's not working

const storage = new GridFsStorage({
  url: mongoURI,

  file: (req, file) => {
    return new Promise((resolve, reject) => {
      const filename = req.params.userID;
      const fileInfo = {
        filename: filename,
        bucketName: "ProfilePic", 
      };
      resolve(fileInfo);
    });
  }
});

const upload = multer({ storage });

router.post("/setProfilePic/:userID", upload.single("picture"), async(req, res) => {
//code not working
  await sharp(req.file.path)
    .resize(500)
    .jpeg({quality: 50})
    .toFile(
        path.resolve(req.file.destination,'resized',image)
    )
// end of non working code
  return res.status(200).json({state: "ok"})
});

Solution

  • My solution is to use the fromStream method from 'multer-gridfs-storage'

    The idea goes like this:

    1. Use multer to parse the file, get the file buffer (raw data)
    2. Use sharp to catch the input buffer and create another buffer that contains the resized image.
    3. Use Readable to create a readable stream, then apply fromStream method to pipe the stream to the database.

    Implementation

    const multer = require('multer')
    const { GridFsStorage } = require("multer-gridfs-storage");
    const { Readable } = require("stream"); // from nodejs
    const sharp = require("sharp");
    
    const storage = new GridFsStorage({
      url: mongoURI,
      options: { useUnifiedTopology: true }, // silence the warning
      file: () => ({ bucketName: "ProfilePic",filename: req.params.userID }),
    });
    
    router.post("/setProfilePic/:userID",multer().single('picture'),(req,res) => {
      const file = req.file
      const buffer = file.buffer
    
      // chain sharp methods
      sharp(buffer)
        .resize(500)
        .jpeg({ quality: 50 })
        .toBuffer((err, data, info) => {
    
          // data here directly contains the buffer object.
          const fileStream = Readable.from(data);
    
          // write the resized stream to the database.
          storage.fromStream(fileStream, req, file).then(() => {
            res.json({ state: 'ok' });
          });
        });
    })
    

    Instead of making full use of the multer's storage engine, I create my own stream.

    I am also a MongoDB beginner, so I am happy enough to make it work. If it doesn't work, please leave a comment and I will try my best to solve it.