Skip to content

Is it possible to convert a buffer to base64string in populate mongoose?

I have a mongoose Image Schema as below:

const ImageSchema = new mongoose.Schema({
    img:
    {
        data: Buffer,
        contentType: String
    }
})

mongoose.model('Image',ImageSchema)

and a Chapter schema

const chapterSchema = new mongoose.Schema({
        chapter_no:{ type: Number, min: 0, max: 50 },
        published:Boolean,
        u_img:{type:mongoose.Schema.Types.ObjectId, ref:"Image"}
        
})
mongoose.model('Chapter', chapterSchema)

I’ll do population for the image

Chapter.find()
    .populate({
        path:"u_img",
        select:["img"]
    })

    .exec(function(err,chapters){
        if(err) res.send(err)
        res.send(chapters)
    })

and I’m trying to convert the buffer to base64string for every single image in the chapter. Could anyone please help me? is there a way to do conversion on populate function in mongoose? or I have to map and doing conversion inside the exec func? or is there another way?

Answer

Well, populate area of concern is more about stitching related documents (in your case images for a given chapter) together than massaging those documents into some usable state.

Still, there’s an option you might find helpful (introduced in Mongoose 5.12):

[options.transform=null] «Function» Function that Mongoose will call on every populated document that allows you to transform the populated document.

So you can modify your query like this:

Chapter.find()
  .populate({
    path:"u_img",
    select:["img"],
    options: {
      transform: doc => new Buffer(doc.data).toString('base64')
    }
  })

As alternative, you can do this transformation of stitched entities in your exec function, like this:

.exec(function(err, chapters){
  if(err) res.send(err)
  chapters.forEach(chapter => { 
    chapter.img = new Buffer(chapter.img.data).toString('base64');
  });
  res.send(chapters)
})

… basically following the receipt given here.