I have a for loop that inserts documents in MongoDB. Using async series I run the loop five times then close the connection. For some strange reason I get an insert error when the loop is executed for the sixth time. I am just not sure what is happening here. Any ideas?
var mycollection= "abcd";
var count = 5;
var db;
var col;
async.series([
// Connect to DB
function(callback) {
MongoClient.connect("mongodb://connection-path-here",function(error, db2) {
if (error) {console.log("db connect error");callback(error,"db connect error"); return;}
db = db2;
callback(null,"connect success");
});
},
function(callback) {
col = db.collection(mycollection);
callback(null,"collection success");
},
function(callback) {
console.log ("insert begin ...");
for (var i = 1; i <= count; i++) {
console.log("inserting ....." + i);
col.insert({c:i}, function(error,result) {
if (error) {console.log("insert error:" + i);callback(error,"insert error"); return;}
});
}
callback(null,"insert success");
},
function (callback){
console.log ("close db");db.close();
callback(null,"connection closed");
}
], function(error, results) {
if (error) { console.log("error"); }
console.log(results);
});
output
insert begin ...
inserting .....1
inserting .....2
inserting .....3
inserting .....4
inserting .....5
close db
insert error:6
error
[ 'connect success', 'collection success', 'insert error' ]
insert error:6
insert error:6
insert error:6
insert error:6
You started well but you are mixing async and non-async methods here:
function(callback) {
console.log ("insert begin ...");
for (var i = 1; i <= count; i++) {
console.log("inserting ....." + i);
col.insert({c:i}, function(error,result) {
if (error) {console.log("insert error:" + i);callback(error,"insert error"); return;}
});
}
callback(null,"insert success");
},
This does not wait for the insert to complete before iterating the next loop, so you need something that waits. Try "async.whilst":
function(callback) {
var i = 1;
async.whilst(
function() { return i <= count },
function(callback) {
col.insert({ c: i },function(error,result) {
if (error)
console.log("insert error:" + i);
i++;
callback(error);
});
},
function(error) {
callback(error,"insert sucess")
}
);
},
The rest can proceed as you are doing and the results will be sent to the end of the series execution.
All of your async operations should be a function in the "operations" array that you are executing. Your for loop calls col.insert() 6 times but before the 6th operation can complete you are calling callback(null, "insert success") - this will cause a race condition so sometimes it may actually make it all the way through or maybe it will only insert a couple of records depending on how long each insert takes.
See the modified code below to fix the issue:
var mycollection= "abcd";
var count = 5;
var db;
var col;
// create operations array with first two operations
var operations = [
// Connect to DB
function(callback) {
MongoClient.connect("mongodb://connection-path-here",function(error, db2) {
if (error) {console.log("db connect error");callback(error,"db connect error"); return;}
db = db2;
callback(null,"connect success");
});
},
function(callback) {
col = db.collection(mycollection);
callback(null,"collection success");
}
];
// push each insert into operations as its own individual operation
for (var i = 1; i <= count; i++) {
operations.push(function(callback){
console.log("inserting ....." + i);
col.insert({c:i}, function(error,result) {
if (error) {console.log("insert error:" + i);callback(error,"insert error"); return;}
// no errors here, so this insert was successful!
callback(null);
});
})
}
// finish pushing the last two operations
operations.push(function(callback) {
callback(null,"insert success");
});
operations.push(function (callback){
console.log ("close db");db.close();
callback(null,"connection closed");
});
// execute all the operations
async.series(operations, function(error, results) {
if (error) { console.log("error"); }
console.log(results);
});