Le problème ici est que la boucle que vous exécutez n'attend pas la fin de chaque opération. Donc, en fait, vous ne faites que mettre en file d'attente des milliers de .save()
requêtes et en essayant de les exécuter simultanément. Vous ne pouvez pas le faire dans des limites raisonnables, vous obtenez donc la réponse d'erreur.
Le async module a diverses méthodes pour itérer lors du traitement d'un rappel pour cet itérateur, où le for direct le plus simple est probablement whilst . Mongoose gère également la gestion des connexions pour vous sans avoir besoin d'intégrer le rappel, car les modèles sont conscients de la connexion :
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
}
);
Ce n'est pas la façon la plus fantastique de le faire, c'est toujours une écriture à la fois et vous pouvez utiliser d'autres méthodes pour "gouverner" les opérations simultanées, mais cela au moins ne fera pas exploser la pile des appels.
Depuis MongoDB 2.6 et les versions ultérieures, vous pouvez utiliser l'API d'opérations en masse afin de traiter plus d'une écriture à la fois sur le serveur. Le processus est donc similaire, mais cette fois vous pouvez envoyer 1000 à la fois au serveur en une seule écriture et réponse, ce qui est beaucoup plus rapide :
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
});
}
);
});
Cela utilise en fait les méthodes de pilote natives qui ne sont pas encore exposées dans la mangouste, de sorte que des précautions supplémentaires sont prises pour s'assurer que la connexion est disponible. C'est un exemple mais pas le seul moyen, mais le point principal est que la "magie" de la mangouste pour les connexions n'est pas intégrée ici, vous devez donc vous assurer qu'elle est établie.
Vous avez un nombre rond d'éléments à traiter, mais là où ce n'est pas le cas, vous devriez appeler le bulk.execute()
dans ce dernier bloc ainsi que montré, mais cela dépend du nombre répondant au modulo.
Le point principal est de ne pas développer une pile d'opérations à une taille déraisonnable et de limiter le traitement. Le contrôle de flux permet ici des opérations qui prendront un certain temps avant de passer à l'itération suivante. Ainsi, les mises à jour par lots ou une mise en file d'attente parallèle supplémentaire sont ce que vous voulez pour de meilleures performances.
Il y a aussi le .initializeUnorderedBulkOp()
form pour cela si vous ne voulez pas que les erreurs d'écriture soient fatales, mais gérez-les d'une manière différente à la place. Consultez principalement la documentation officielle sur l'API de transfert en masse et les réponses pour savoir comment interpréter la réponse donnée.