sql >> Base de Datos >  >> NoSQL >> MongoDB

Nodo inserta datos grandes usando mangosta

El problema aquí es que el bucle que está ejecutando no está esperando a que se complete cada operación. Entonces, de hecho, solo está poniendo en cola miles de .save() solicitudes e intentar ejecutarlas simultáneamente. No puede hacer eso dentro de limitaciones razonables, por lo que obtiene la respuesta de error.

El async El módulo tiene varios métodos para iterar mientras procesa una devolución de llamada para ese iterador, donde probablemente el directo más simple sea . Mongoose también maneja la administración de la conexión por usted sin necesidad de integrarse en la devolución de llamada, ya que los modelos son conscientes de la conexión:

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
    }
);

No es la forma más fantástica de hacerlo, sigue siendo una escritura a la vez y podría usar otros métodos para "gobernar" las operaciones concurrentes, pero esto al menos no hará estallar la pila de llamadas.

Desde MongoDB 2.6 y superior, puede utilizar la API de operaciones masivas para procesar más de una escritura a la vez en el servidor. Entonces, el proceso es similar, pero esta vez puede enviar 1000 a la vez al servidor en una sola escritura y respuesta, que es mucho más 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
            });
      }
    );

});

En realidad, se utilizan los métodos de controlador nativo que aún no están expuestos en mongoose, por lo que se está tomando un cuidado adicional para asegurarse de que la conexión esté disponible. Ese es un ejemplo, pero no la única forma, pero el punto principal es que la "magia" de la mangosta para las conexiones no está integrada aquí, por lo que debe asegurarse de que esté establecida.

Tiene una cantidad redonda de elementos para procesar, pero cuando no sea el caso, debe llamar a bulk.execute() en ese bloque final como se muestra, pero depende del número que responda al módulo.

El punto principal es no hacer crecer una pila de operaciones a un tamaño irrazonable y mantener el procesamiento limitado. El control de flujo aquí permite operaciones que tardarán algún tiempo en completarse antes de pasar a la siguiente iteración. Por lo tanto, las actualizaciones por lotes o algunas colas paralelas adicionales son lo que desea para obtener el mejor rendimiento.

También está el .initializeUnorderedBulkOp() form para esto si no desea que los errores de escritura sean fatales, sino que los manipule de una manera diferente. En su mayoría, consulte la documentación oficial sobre la API masiva y las respuestas para saber cómo interpretar la respuesta dada.