MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

Node insere grandes dados usando mangusto


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.