John John - 2 months ago 24
Node.js Question

Mongoose save loop lost iterator

I have to save lot of object in my database with mongoose.

Here is an example of my code :

for (var i = 0; i < userdata.length; i++) {

var newCompany = Company({
name: userdata[i].company_name
});

newCompany.save(function(err, c) {
if (err) throw err;

var newGeoloc = Geolocation({
latitude: userdata[i].latitude,
longitude: userdata[i].longitude
});

newGeoloc.save(function(err, g) {
if (err) throw err;

// Create new Office
var newOffice = Office({
name : userdata[i].office_name,
address : userdata[i].address,
city : userdata[i].city,
zip_code : userdata[i].zip_code,
geolocation : g._id,
company : c._id
});

// Save the Office
newOffice.save(function(err, officeCreated) {
if (err) throw err;

console.log('Office created!');

});
});
}


Why my
i
variable when I save the geolocation object
latitude: datas[i].latitude
got the max length of my array
userdata.length
? E.g if userdata has 150 object, I'll get always 150 when I create the geolocation object.

How can I do ?

Answer

Since the for loop runs without waiting for the callback to be received in the save functions, you can use closures to keep the value of i local to the self invoking function as shown below.

for (var i = 0; i < userdata.length; i++) {
    (
        function(index) {
            var newCompany = Company({
                name: userdata[index].company_name
            });

            newCompany.save(function(err, c) {
                if (err) throw err;

                var newGeoloc = Geolocation({
                    latitude: userdata[index].latitude,
                    longitude: userdata[index].longitude
                });

                newGeoloc.save(function(err, g) {
                    if (err) throw err;
                    var newOffice = Office({
                        name        : userdata[index].office_name,
                        address     : userdata[index].address,
                        city        : userdata[index].city,
                        zip_code    : userdata[index].zip_code,
                        geolocation : g._id,
                        company     : c._id
                    });

                    // Save the Office
                    newOffice.save(function(err, officeCreated) {
                        if (err) throw err;
                        console.log('Office created!');
                    });
                });

           });
        }
    )(i);
}

When the self invoking function is called each time the loop is run, the value of i is copied to the variable index.