Problemet här är att slingan du kör inte väntar på att varje operation ska slutföras. Så i själva verket står du bara i kö i 1000-tals .save()
förfrågningar och försöker köra dem samtidigt. Du kan inte göra det inom rimliga gränser, därför får du felsvaret.
async modulen har olika metoder för att iterera under bearbetning av en återuppringning för den iteratorn, där förmodligen den enklaste direkt för är medan . Mongoose sköter även anslutningshanteringen åt dig utan att behöva bädda in i återuppringningen, eftersom modellerna är anslutningsmedvetna:
var tempColSchema = new Schema({
cid: {
type: Number,
required: true
},
loc:[]
});
var TempCol = mongoose.model( "TempCol", tempColSchema );
mongoose.connect( 'mongodb://localhost/mean-dev' );
var i = 0;
async.whilst(
function() { return i < 10000000; },
function(callback) {
i++;
var c = i;
console.log(c);
var lon = parseInt(c/100000);
var lat = c%100000;
new Tempcol({cid: Math.random(), loc: [lon, lat]}).save(function(err){
callback(err);
});
},
function(err) {
// When the loop is complete or on error
}
);
Inte det mest fantastiska sättet att göra det, det är fortfarande en skrivning i taget och du kan använda andra metoder för att "styra" de samtidiga operationerna, men detta kommer åtminstone inte att spränga samtalsstacken.
Från MongoDB 2.6 och senare kan du använda Bulk Operations API för att bearbeta mer än en skrivning åt gången på servern. Så processen är liknande, men den här gången kan du skicka 1000 åt gången till servern i en enda skrivning och ett svar, vilket är mycket snabbare:
var tempColSchema = new Schema({
cid: {
type: Number,
required: true
},
loc:[]
});
var TempCol = mongoose.model( "TempCol", tempColSchema );
mongoose.connect( 'mongodb://localhost/mean-dev' );
mongoose.on("open",function(err,conn) {
var i = 0;
var bulk = TempCol.collection.initializeOrderedBulkOp();
async.whilst(
function() { return i < 10000000; },
function(callback) {
i++;
var c = i;
console.log(c);
var lon = parseInt(c/100000);
var lat = c%100000;
bulk.insert({ "cid": Math.random(), "loc": [ lon, lat ] });
if ( i % 1000 == 0 ) {
bulk.execute(function(err,result) {
bulk = TempCol.collection.initializeOrderedBulkOp();
callback(err);
});
} else {
process.nextTick(callback);
}
},
function(err) {
// When the loop is complete or on error
// If you had a number not plainly divisible by 1000
if ( i % 1000 != 0 )
bulk.execute(function(err,result) {
// possibly check for errors here
});
}
);
});
Det är faktiskt att använda de inhemska drivrutinsmetoderna som ännu inte är exponerade i mongoose, så den extra försiktighet som vidtas för att se till att anslutningen är tillgänglig. Det är ett exempel men inte det enda sättet, men huvudpoängen är att mangust-"magin" för anslutningar inte är inbyggd här så du bör vara säker på att den är etablerad.
Du har ett runt antal objekt att bearbeta, men där det inte är fallet bör du anropa bulk.execute()
i det sista blocket så väl som visas, men det beror på numret som svarar på modulo.
Huvudpoängen är att inte växa en stapel av operationer till en orimlig storlek och hålla bearbetningen begränsad. Flödeskontrollen här tillåter operationer som kommer att ta lite tid att faktiskt slutföra innan du går vidare till nästa iteration. Så antingen batchuppdateringar eller ytterligare parallellköer är vad du vill ha för bästa prestanda.
Det finns också .initializeUnorderedBulkOp()
formulär för detta om du inte vill att skrivfel ska vara ödesdigra utan hantera dem på ett annat sätt istället. Se mestadels den officiella dokumentationen om Bulk API och svar för hur man tolkar svaret som ges.