O problema aqui é que o loop que você está executando não está aguardando a conclusão de cada operação. Então, na verdade, você está apenas enfileirando milhares de
.save()
solicitações e tentar executá-las simultaneamente. Você não pode fazer isso dentro de limitações razoáveis, portanto, obtém a resposta de erro. O assíncrono O módulo tem vários métodos para iterar enquanto processa um retorno de chamada para esse iterador, onde provavelmente o mais simples é enquanto . O Mongoose também lida com o gerenciamento de conexão para você sem precisar incorporar no retorno de chamada, pois os modelos reconhecem a conexão:
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
}
);
Não é a maneira mais fantástica de fazer isso, ainda é uma gravação de cada vez e você pode usar outros métodos para "governar" as operações simultâneas, mas isso pelo menos não explodirá a pilha de chamadas.
No MongoDB 2.6 e superior, você pode usar a API de operações em massa para processar mais de uma gravação por vez no servidor. Portanto, o processo é semelhante, mas desta vez você pode enviar 1000 por vez para o servidor em uma única gravação e resposta, o que é muito mais rápido:
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
});
}
);
});
Na verdade, isso está usando os métodos de driver nativos que ainda não foram expostos no mangusto, portanto, o cuidado adicional está sendo tomado para garantir que a conexão esteja disponível. Esse é um exemplo, mas não o único caminho, mas o ponto principal é que a "mágica" do mangusto para conexões não está embutida aqui, então você deve ter certeza de que está estabelecido.
Você tem um número redondo de itens para processar, mas onde não for o caso, você deve chamar o
bulk.execute()
nesse bloco final, bem como mostrado, mas depende do número que responde ao módulo. O ponto principal é não aumentar uma pilha de operações para um tamanho excessivo e manter o processamento limitado. O controle de fluxo aqui permite operações que levarão algum tempo para serem realmente concluídas antes de passar para a próxima iteração. Portanto, as atualizações em lote ou algum enfileiramento paralelo adicional é o que você deseja para obter o melhor desempenho.
Há também o
.initializeUnorderedBulkOp()
form para isso se você não quiser que os erros de gravação sejam fatais, mas trate-os de uma maneira diferente. Veja principalmente a documentação oficial da API em massa e as respostas para saber como interpretar a resposta dada.