Search code examples
node.jsmongodbmongoskin

MongoSkin wrong insertion


I have an array with countries with the following structure:

{
    "code": "ZW",
    "name": "Zimbabwe",
    "zipPattern": "[\\s\\S]*",
    "states": [
        {
            "name": "Bulawayo"
        },
        {
            "name": "Harare"
        },
        {
            "name": "Manicaland"
        },
        {
            "name": "Mashonaland Central"
        },
        {
            "name": "Mashonaland East"
        },
        {
            "name": "Mashonaland West"
        },
        {
            "name": "Masvingo"
        },
        {
            "name": "Matabeleland North"
        },
        {
            "name": "Matabeleland South"
        },
        {
            "name": "Midlands"
        }
    ]
}

I am trying to insert them into MongoDb using MongoSkin with the following code

var countries = require('./mongo/ready/Countries');
db.collection('countries').find().toArray(function (err, result) {
  if (result.length === 0) {
    for (var i = 0; i < countries.length; i++) {
        var obj = countries[i];
        var states = obj.states;
        db.collection('countries').insert({
            name: obj.name,
            code: obj.code,
            zipPattern: obj.zipPattern
        }, function (error, countryResult) {
            var id = countryResult[0]._id;

            for (var j = 0; j < states.length; j++) {
                var state = states[j];
                db.collection('states').insert({
                    countryId: id,
                    name: state.name
                }, function (stateError, stateResult) {
                    if (stateError) console.log(stateError);
                     console.log(stateResult);
                });
            }
        });
    }
  }
});

but the code inserts the states of the last country in the array (Zimbabwe) for each country in the array instead of the correct states. How can I fix it?


Solution

  • Generally we don't use async query(insert) between sync loop(simple for loop). Its give us abnoramal results. Node provides async loop to overcome this.

    First of all require async module for this.

    var async = require('async');
    

    Now you can use following code for insertion of countries and their respective states

    async.each(countries, function(obj, callback) {
    
        var states = obj.states;
        db.collection('countries').insert({
            name: obj.name,
            code: obj.code,
            zipPattern: obj.zipPattern
        }, function(error, countryResult) {
            if (error) {
                callback(error);
            } else {
                var id = countryResult[0]._id;
                async.each(states, function(state, callback) {
                    db.collection('states').insert({
                        countryId: id,
                        name: state.name
                    }, function(stateError, stateResult) {
                        if (stateError) {
                            callback(stateError);
                        } else {
                            callback();
                        }
    
                    });
                });
                callback();
            }
        }); }, function(err) {
        if (err) {
            // handle error here
        } else {
           // do stuff on completion of insertion
        } });
    

    Thanks