1

I am trying to replace a string in url . Here is image of it

enter image description here

in this image I want to replace lssplalpha with lssplprod which are in pics array. For that I created an api . Here is a code

apiRoutes.get('/SchoolListing_lssplalpha_Replace',function(req, res) { schoolListModel.find({},function(err,check){     
    if(err){        
    return console.log(err); 
        }       
    else{
        for(var i=0;i<check.length;){
            var f=0;
        for(var j=0;j<check[i].pics.length;j++){
               f++;                     
        var newTitle =  check[i].pics[j].replace("lssplalpha","lsslprod");    
         check[i].pics[j] = newTitle; 
         console.log("after change",check[i].pics[j]);
         check[i].save(function (err) {
                if(err) {
                    console.error('ERROR!');
                }
            }); 
}    
if(j==check[i].pics.length&&j==f){  
    i++; 
}       
 } 
console.log("i value",i);
 console.log("check length",check.length); 
if(i==check.length){        
            return res.json({status:true,message:"Updated Schools"});           }   
    } 
    }); 
 });

I am getting success response . When I go and check database nothing changed in db. To know the reason I write log of it. When I see logs it was replacing correctly. But I didn't understand why those are not reflecting in database? Here is an image of log in console enter image description here

Please help me to come out of this

2 Answers 2

1

The issue here is you are running a for loop (synchronous) where you are calling the model.save() operation which is asynchronous and the loop keeps iterating but the results of the async calls come later. The process of saving a database item in an array takes some time and Node.js knows this, so it starts the update and then just moves on trying to update the next item in the array. Once the write operation is complete a callback function is run, but by that point the loop has completed and there is no way to know which items finish in what order.

You could use the Bulk Write API to update your models. This allows you to sends multiple write operations to the MongoDB server in one command. This is faster than sending multiple independent operations (like) if you use create()) because with bulkWrite() there is only one round trip to MongoDB.

The following examples show how you can use the bulkWrite.

Using async/await:

apiRoutes.get('/SchoolListing_lssplalpha_Replace', async (req, res) => { 

    try {
        let ops = [];
        const docs = await schoolListModel.find({}).lean().exec();

        docs.forEach(doc => {
            const pics = doc.pics.map(pic => pic.replace("lssplalpha", "lsslprod"));

            ops.push({
                "updateOne": {
                    "filter": { "_id": doc._id },
                    "update": {
                        "$set": { pics }
                    }
                }
            });                    
        });     

        const result = await schoolListModel.bulkWrite(ops);  

        console.log('Bulk update complete.', result); 
        res.status(200).json({
            status: true,
            message: "Updated Schools"
        }); 

    } catch (err) {
        res.status(400).send({
            status: false,
            message: err 
        });
    }
});

Using Promise API:

const bulkUpdate = (Model, query) => (    
    new Promise((resolve, reject) => {
        let ops = [];

        Model.find(query).lean().exec((err, docs) => {
            if (err) return reject(err);

            docs.forEach(doc => {
                const pics = doc.pics.map(pic => (
                    pic.replace("lssplalpha", "lsslprod")
                ));

                ops.push({
                    "updateOne": {
                        "filter": { "_id": doc._id },
                        "update": {
                            "$set": { pics }
                        }
                    }
                });

                if (ops.length === 500) {
                    Model.bulkWrite(ops).then((err, result) => {
                        if (err) return reject(err);                        
                        ops = [];
                        resolve(result);
                    });
                }                       
            });     

            if (ops.length > 0) {            
                Model.bulkWrite(ops).then((err, result) => {
                    if (err) return reject(err);
                    resolve(result);
                });         
            }           
        });     
    })
);

apiRoutes.get('/SchoolListing_lssplalpha_Replace', (req, res) => { 
    bulkUpdate(schoolListModel, {}).then(result => {
        console.log('Bulk update complete.', result); 
        res.status(200).json({
            status: true,
            message: "Updated Schools"
        });    
    }).catch(err => {
        res.status(400).send({
            status: false,
            message: err 
        });
    });
});
Sign up to request clarification or add additional context in comments.

Comments

1

You are running asynchronous call model.save() in for loop(synchronous)

To make your for loop synchronous you can use for...of loop which works asynchronous, also you will not need to add multiple checks like you have done in your code.

Try following code, it will work

apiRoutes.get('/SchoolListing_lssplalpha_Replace', function (req, res) {
schoolListModel.find({},function (err, check) {
    if (err) {
        return console.log(err);
    }
    else {
        for (let checkObj of check) {
            let newPicArr=[];
            for (let pic of checkObj.pics) {
                pic = pic.replace("lssplalpha", "lsslprod");
                newPicArr.push(pic);
            }
            checkObj.pics=newPicArr;
            checkObj.save(function (err) {
                if (err) {
                    console.error('ERROR!');
                }
            });     
        }
        return res.json({ status: true, message: "Updated Schools" });
    }
   });
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.