Search code examples
node.jsexpressmongoosedynamic-programmingmongoose-populate

Populate Dynamic Fields Mongoose


I'm trying to create a dynamic function that gets an array of fields, filter object, and a schema model, and populates the fields in the array.

for example: instead of populating like this-

getCardByName=(Model,filter)=>{ 
         return new Promise((resolve, reject) => {
             Model.findOne(filter).populate({ path: "user" })
                 .populate({ path: "socialMedia" })
                 .populate({ path: 'galleryList' })
                 .populate({ path: 'reviewsList' })
                 .populate({ path: 'lead' })
                 .populate({ path: 'statistic', })
                 .exec(async(err, card) => {
                     if (err) {
                         reject(err);
                     }
                     resolve(card)
                 })
       });
}

I want to create a dynamic function something like this:

 //assume arr is a function argument
    arr=["user", "socialMedia", "galleryList", "reviewsList", "lead", "statistic"]
    let populateStr=""
        arr.forEach(path => {
            populateStr+=`.populate({path: ${path}})`
        });
        console.log(populateStr)
        return new Promise(async(resolve, reject)=>{
            try{
              await Model.findOne(filter).populateStr
              .exec(async(err,card)=>{
                  if(err)
                  {
                      reject(err)
                      resolve(card)
                  }
              })

              }
        catch(err){
    console.log(err)
    }
    })

when I run this code, I get the population string but the population itself doesn't really happen.

(TypeError: Cannot read property 'exec' of undefined)

Do you have any idea of doing it or fixing the code I wrote?

Thank you!


Solution

  • You can do something like this

    var query = Model.findOne(filter);
    
    arr.forEach(path => {
        query.populate(path);
    });
    
    query.exec(async (err, card) => {
        if (err)
            reject(err)
        else 
            resolve(card)
    });
    

    There's no reason to use await for Model.findOne when you use resolve/reject in the exec calback function. Also no need for try/catch.