Having trouble iterating through array and saving to mongoose. Callback issue? Having trouble iterating through array and saving to mongoose. Callback issue? express express

Having trouble iterating through array and saving to mongoose. Callback issue?


The problem with this is that the story referenced in the exec callback will have been set to whatever is the last thing iterated on in the for loop, once the callback will get executed, since all of the executed functions are referencing the same instance of the variable.

The easiest way to fix this is to simply wrap each thing in the for loop in a function that you execute right away with parameters, as in:

rssparser.parseURL(url, options, function(err,out){    // out.items is an array of the items pulled    var items = out.items;    for (var i=0; i<items.length; i++){        (function(item) {            //create a mongoose story            var story = new schemas.Stories({                title: item.title,                url: item.url,                summary: item.summary,                published: item.published_at            });            // setup query to see if it's already in db            var query = schemas.Stories.findOne({                "title" : story.title,                "url" : story.url            });            //execute the query            query.exec( function(err, row){                if(err) console.log("error-query: " + err);                console.log("row: "+ row);                if(!row) {                    // not there, so save                    console.log('about to save story.title: ' + story.title);                    story.save(function (err){                        console.log("error in save: " + err);                    });                }            });        })(items[i]);    }});

I haven't tested this, but I'm sure you'll find that it will fix your issue

Another even easier, cleaner, better way would be to iterate over the items in a forEach loop on the array, if your platform supports that (which node.js does) - this version is even more prettier:

rssparser.parseURL(url, options, function(err,out){    // out.items is an array of the items pulled    out.items.forEach(function(item) {        //create a mongoose story        var story = new schemas.Stories({            title: item.title,            url: item.url,            summary: item.summary,            published: item.published_at        });        // setup query to see if it's already in db        var query = schemas.Stories.findOne({            "title" : story.title,            "url" : story.url        });        //execute the query        query.exec( function(err, row){            if(err) console.log("error-query: " + err);            console.log("row: "+ row);            if(!row) {                // not there, so save                console.log('about to save story.title: ' + story.title);                story.save(function (err){                    console.log("error in save: " + err);                });            }        });    });});


well, node is event driven server and javascript is also event driven, so you can call stuff asynchronously.

you need to use some async patterns to do what you want.

first, if you are using mongoose you can utilize it's schema class to check for items that are already exists without querying the db again:

var mongoose = require('mongoose');var schema = new mongoose.Schema({    title: String,    url: { type: String, unique: true },    summary: String,    published: Date})var model = mongoose.model('stories', schema)

the url is unique, so the save will cause a duplicate error and mongoose won't save the query.

now to iterate through the items and save each one we need some kind of a pattern for it, luckily we have async for it:

var async = require('async');rssparser.parseURL(url, options, function(err, out){    async.each(out.items, function(item, callback){        var m = new model({            title: item.title,            url: item.url,            summary: item.summary,            published: item.published_at        })        m.save(function(err, result){            callback(null)        });    }, function(err){        //we complete the saving we can do stuff here           });}

we used async in a parallel mode as we don't care if some are duplicate or not.you can also track it with an array that you can push to it the err || result so you can see how many items you saved.