Problém je v tom, že smyčka, kterou spouštíte, nečeká na dokončení každé operace. Takže ve skutečnosti jen řadíte do fronty 1000 .save()
požadavky a pokusit se je spustit souběžně. Nemůžete to udělat v rámci rozumných omezení, proto dostanete chybovou odpověď.
async modul má různé metody pro iteraci při zpracování zpětného volání pro tento iterátor, kde pravděpodobně nejjednodušší přímý pro je zatímco . Mongoose se také stará o správu připojení za vás, aniž byste museli vkládat do zpětného volání, protože modely připojení znají:
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
}
);
Není to nejfantastičtější způsob, jak to udělat, stále je to jeden zápis po druhém a můžete použít jiné metody pro "řízení" souběžných operací, ale to alespoň nevyhodí do vzduchu zásobník volání.
Formulář MongoDB 2.6 a vyšší můžete využít Bulk Operations API za účelem zpracování více než jednoho zápisu najednou na serveru. Proces je tedy podobný, ale tentokrát můžete na server poslat 1000 najednou v jediném zápisu a odpovědi, což je mnohem rychlejší:
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
});
}
);
});
To ve skutečnosti používá metody nativního ovladače, které ještě nejsou v mongoose vystaveny, takže je věnována další péče tomu, aby bylo připojení k dispozici. To je příklad, ale ne jediný způsob, ale hlavním bodem je, že „kouzlo“ pro spojení zde není zabudováno, takže byste si měli být jisti, že je navázáno.
Máte kulatý počet položek ke zpracování, ale pokud tomu tak není, měli byste volat bulk.execute()
v tomto posledním bloku, stejně jako na obrázku, ale záleží na čísle, které odpovídá na modulo.
Hlavním bodem je nenarůstat hromadu operací do nepřiměřené velikosti a udržovat omezené zpracování. Řízení toku zde umožňuje operace, jejichž skutečné dokončení bude nějakou dobu trvat, než se přejde k další iteraci. Pro nejlepší výkon tedy chcete buď dávkové aktualizace, nebo nějaké další paralelní řazení do fronty.
Existuje také .initializeUnorderedBulkOp()
formulář pro toto, pokud nechcete, aby byly chyby při zápisu fatální, ale místo toho s nimi nakládejte jiným způsobem. Většinou se podívejte na oficiální dokumentaci k Bulk API a odpovědi, jak interpretovat danou odpověď.