2017-03-21 2 views
0

que je recevais cette JSON:Node.js + OracleDb - Insérez la dernière date plusieurs fois

{ 
    "TOTAL_RECORDS": 1029, 
    "REGISTROS": [ 
    { 
     "CODIGO": "1", 
     "ATENDIMENTO": "1", 
     "PAGAMENTO": "1", 
     "VENCIMENTO": "2016-12-17 00:00:00", 
     "PROCESSAMENTO": "2016-12-10 00:00:00", 
     "VALOR": "1800.00000", 
     "NOSSO_NUMERO": "xxxxxxx", 
     "NUMERO_DOCUMENTO": "xxxxx", 
     "CODIGO_BANCO": "123", 
     "LINHA_DIGITAVEL": "XXX70110000180000", 
     "CODIGO_BARRAS": "XXX90940" 
    }, 
    { 
     "CODIGO": "2", 
     "ATENDIMENTO": "2", 
     "PAGAMENTO": "2", 
     "VENCIMENTO": "2016-12-17 00:00:00", 
     "PROCESSAMENTO": "2016-12-10 00:00:00", 
     "VALOR": "2700.00000", 
     "NOSSO_NUMERO": "xxxxxxx", 
     "NUMERO_DOCUMENTO": "xxxxx", 
     "CODIGO_BANCO": "123", 
     "LINHA_DIGITAVEL": "XXX70110000180000", 
     "CODIGO_BARRAS": "XXX90940" 
    },... 

Je dois attraper cette info et enregistrer dans DB Oracle, donc je le fais:

module.exports = function (object, callback) { 

    var oracledb = require('oracledb');  
    for(const prop in object['REGISTROS']){      

     codigo = object['REGISTROS'][prop]['CODIGO'];    

     atendimento = object['REGISTROS'][prop]['ATENDIMENTO']; 

     pagamento = object['REGISTROS'][prop]['PAGAMENTO']; 

     vencimento = object['REGISTROS'][prop]['VENCIMENTO']; 

     processamento = object['REGISTROS'][prop]['PROCESSAMENTO']; 

     valor = parseInt(object['REGISTROS'][prop]['VALOR']); 

     nossoNumero = object['REGISTROS'][prop]['NOSSO_NUMERO']; 

     numeroDocumento = object['REGISTROS'][prop]['NUMERO_DOCUMENTO']; 

     codigoBanco = object['REGISTROS'][prop]['CODIGO_BANCO']; 

     linhaDigitavel = object['REGISTROS'][prop]['LINHA_DIGITAVEL'];    

     codigoBarras = object['REGISTROS'][prop]['CODIGO_BARRAS']; 

     oracledb.getConnection({    
      user: "x", 
      password:"xxx", 
      connectString: "mycon/string" 
     }, 
     function(err, connection){ 
      if (err){ 
       console.error(err.message); 
       return; 
      } 

      connection.execute(
       "INSERT INTO USU_TBOLETO VALUES (:USU_CODIGO, :USU_ATEND, :USU_PAGAMENTO, " + 
       ":USU_VENCIMENTO, :USU_PROCESSA, :USU_VALOR, :USU_NOSSONUM, :NUMERODOC, :USU_CODBANCO, " + 
       ":USU_LINHADIG , :USU_CODBARRAS)", 

      [codigo, atendimento, pagamento, vencimento, processamento, valor, nossoNumero, 
      numeroDocumento, codigoBanco, linhaDigitavel, codigoBarras], 
      { autoCommit: true},    
      function(err, result){ 

       if (err){ 
        console.error(err.message);    
        doRelease(connection); 
        return; 
       } 
       console.log(codigo + ' - ' + atendimento + ' - ' + pagamento + ' - ' + vencimento); 
       ///console.log(result.metaData); 
       ///console.log(result.rows); 
       doRelease(connection); 
      });     
     }); 
    } 


    function doRelease(connection) {   
     connection.release( 
      function(err){ 
       if (err) { console.error(err.message); } 
      } 
     ); 
    } 
} 

Et le problème est qu'il est inséré dans ma base de données juste le dernier enregistrement, 1029 fois, comme le nombre total d'enregistrements. Pourquoi? Je ne comprends pas pourquoi. Le code INSERT est dans la condition FOR.

Le bon serait insérer 1029 fois, en commençant Codigo 1 jusqu'à 1029.

Att. Diogo

+0

Votre insertion db est async et probablement prendre un certain temps. Alors que votre boucle 'for' s'exécute presque immédiatement, l'insertion prendra les valeurs de la dernière itération. – abhishekkannojia

+0

Regardez ceci http://stackoverflow.com/questions/11488014/asynchronous-process-inside-a-javascript-for-loop – abhishekkannojia

Répondre

1

Lorsque vous exécutez le code comme vous l'avez actuellement structuré, il enverra beaucoup comme opérations ync à la file d'attente de travail de libuv et votre code JavaScript perd le contrôle. Je recommande d'utiliser le async module's eachSeries method pour maintenir le contrôle ou une chaîne de promesses (ou async/await dans Node.js 7.6+). De plus, obtenir une nouvelle connexion pour chaque itération de la boucle va beaucoup ralentir les choses! Vous n'avez besoin que d'une connexion pour cette opération. Vous devriez obtenir la connexion, traiter les données, fermer la connexion.

Une autre chose à reconsidérer est l'utilisation de autoCommit: true. Si vous faites cela pour chaque ligne, vous traitez chaque insert comme sa propre transaction. Si un échec devait se produire à mi-chemin, déterminer ce qui n'allait pas et le réparer (insérer les lignes restantes) sera difficile et manuel. Je recommande d'utiliser la méthode commit sur l'objet de connexion après que tout a été inséré (ou utilisez autoCommit: true sur la dernière itération de la boucle).

Voici un exemple:

Vous pouvez optimiser encore plus loin en réduisant le nombre de vols aller-retour 1029-1 (en faisant tout à la fois) ou 3 (si vous faites des ensembles de 500 à la fois) . Cela va grandement améliorer les performances. Voici un exemple qui insère des lots de par groupes de 500.

const oracledb = require('oracledb'); 
const config = require('./dbConfig.js'); 

module.exports = function(object, callback) { 
    let conn; 

    function insertRegistros(opts) { 
    if (opts.commit) { 
     console.log('Last iteration of the loop, committing with this one'); 
    } 

    return conn.execute(
    `declare 
     type varchar2_aat is table of varchar2(50) 
      index by pls_integer; 

     l_usu_codigo_vals varchar2_aat; 

     begin 

     l_usu_codigo_vals := :usu_codigo_vals; 

     forall x in 1 .. l_usu_codigo_vals.count 
     insert into usu_tboleto (
      usu_codigo, usu_atend, usu_pagamento, usu_vencimento, usu_processa, usu_valor, 
      usu_nossonum, numerodoc, usu_codbanco, usu_linhadig, usu_codbarras 
     ) values (
      :usu_codigo_vals(x), :usu_atend_vals(x), :usu_pagamento_vals(x), :usu_vencimento_vals(x), :usu_processa_vals(x), :usu_valor_vals(x), 
      :usu_nossonum_vals(x), :numerodoc_vals(x), :usu_codbanco_vals(x), :usu_linhadig_vals(x) , :usu_codbarras_vals(x) 
     ); 

     end;`, 
     { 
     usu_codigo_vals: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: opts.usu_codigo_vals}, 
     usu_atend_vals: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: opts.usu_atend_vals}, 
     usu_pagamento_vals: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: opts.usu_pagamento_vals}, 
     usu_vencimento_vals: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: opts.usu_vencimento_vals}, 
     usu_processa_vals: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: opts.usu_processa_vals}, 
     usu_valor_vals: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: opts.usu_valor_vals}, 
     usu_nossonum_vals: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: opts.usu_nossonum_vals}, 
     numerodoc_vals: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: opts.numerodoc_vals}, 
     usu_codbanco_vals: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: opts.usu_codbanco_vals}, 
     usu_linhadig_vals: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: opts.usu_linhadig_vals}, 
     usu_codbarras_vals: {type: oracledb.STRING, dir: oracledb.BIND_IN, val: opts.usu_codbarras_vals} 
     }, 
     { 
     autoCommit: opts.commit 
     } 
    ); 
    } 

    oracledb.getConnection(config) 
    .then(function(c) { 
     conn = c; 

     console.log('Got connection, starting loop'); 

     const batchRowCount = 500; 
     const loops = Math.ceil(object['REGISTROS'].length/batchRowCount); 

     let promiseChain = Promise.resolve(); 
     let registrosIdx = 0; 

     for (let outerIndex = 0; outerIndex < loops; outerIndex += 1) { 
     (function() { 
      const usu_codigo_vals = []; 
      const usu_atend_vals = []; 
      const usu_pagamento_vals = []; 
      const usu_vencimento_vals = []; 
      const usu_processa_vals = []; 
      const usu_valor_vals = []; 
      const usu_nossonum_vals = []; 
      const numerodoc_vals = []; 
      const usu_codbanco_vals = []; 
      const usu_linhadig_vals = []; 
      const usu_codbarras_vals = []; 

      for (let idx = 0; idx < batchRowCount; idx += 1) { 
      if (registrosIdx === object['REGISTROS'].length) { 
       break; 
      } 

      usu_codigo_vals.push(object['REGISTROS'][registrosIdx].CODIGO); 
      usu_atend_vals.push(object['REGISTROS'][registrosIdx].ATENDIMENTO); 
      usu_pagamento_vals.push(object['REGISTROS'][registrosIdx].PAGAMENTO); 
      usu_vencimento_vals.push(object['REGISTROS'][registrosIdx].VENCIMENTO); 
      usu_processa_vals.push(object['REGISTROS'][registrosIdx].PROCESSAMENTO); 
      usu_valor_vals.push(object['REGISTROS'][registrosIdx].VALOR); 
      usu_nossonum_vals.push(object['REGISTROS'][registrosIdx].NOSSO_NUMERO); 
      numerodoc_vals.push(object['REGISTROS'][registrosIdx].NUMERO_DOCUMENTO); 
      usu_codbanco_vals.push(object['REGISTROS'][registrosIdx].CODIGO_BANCO); 
      usu_linhadig_vals.push(object['REGISTROS'][registrosIdx].LINHA_DIGITAVEL); 
      usu_codbarras_vals.push(object['REGISTROS'][registrosIdx].CODIGO_BARRAS); 

      registrosIdx += 1; 
      } 

      promiseChain = promiseChain 
      .then(function() { 
       return insertRegistros({ 
       usu_codigo_vals: usu_codigo_vals, 
       usu_atend_vals: usu_atend_vals, 
       usu_pagamento_vals: usu_pagamento_vals, 
       usu_vencimento_vals: usu_vencimento_vals, 
       usu_processa_vals: usu_processa_vals, 
       usu_valor_vals: usu_valor_vals, 
       usu_nossonum_vals: usu_nossonum_vals, 
       numerodoc_vals: numerodoc_vals, 
       usu_codbanco_vals: usu_codbanco_vals, 
       usu_linhadig_vals: usu_linhadig_vals, 
       usu_codbarras_vals: usu_codbarras_vals, 
       commit: outerIndex + 1 === loops 
       }); 
      }); 
     })(); 
     } 

     return promiseChain; 
    }) 
    .catch(function(err) { 
     console.log(err); 
     console.log('Encountered error, rolling back transaction'); 

     return conn.rollback() 
     .then(function() { 
      console.log('Transaction rolled back'); 
     }) 
     .catch(function(err) { 
      console.log('Error rolling back', err); 
     }); 
    }) 
    .then(function() { 
     return conn.close(); 
    }) 
    .then(function() { 
     console.log('Connection closed'); 
    }) 
    .catch(function(err) { 
     console.log(err); 
    }); 
} 

Comme vous pouvez le voir, le code devient un peu délicat.Cependant, cela devrait devenir plus simple à l'avenir lorsque le pilote ajoute la prise en charge des tableaux de liaison d'enregistrements plutôt que des chaînes ou des nombres.

Vous pouvez en savoir plus à ce sujet et le travail autour J'utilise sur mon blog ici: https://jsao.io/2017/01/plsql-record-types-and-the-node-js-driver/

+0

Thks Dan! Comme vous le voyez, je suis nouveau dans JS, et votre explication m'a beaucoup aidé! Je suis super intéressé! –

+0

Salut Diogo, j'ai mis à jour la réponse avec un exemple en vrac. J'espère que ça aide! –

0

La boucle for est exécutée presque immédiatement alors que l'opération de base de données est asynchrone et lente. La boucle for doit avoir été terminée au moment où le rappel de l'opération asynchrone a été exécuté et, par conséquent, il ne verra les valeurs que lors de la dernière itération de la boucle. Pour éviter cela, vous pouvez déclarer des variables en utilisant les ES6 const qui créeront la variable de portée de bloc. Modifiez votre code pour cela et il devrait fonctionner:

module.exports = function(object, callback) { 

    var oracledb = require('oracledb'); 
    for (const prop in object['REGISTROS']) { 

     const codigo = object['REGISTROS'][prop]['CODIGO']; 

     const atendimento = object['REGISTROS'][prop]['ATENDIMENTO']; 

     const pagamento = object['REGISTROS'][prop]['PAGAMENTO']; 

     const vencimento = object['REGISTROS'][prop]['VENCIMENTO']; 

     const processamento = object['REGISTROS'][prop]['PROCESSAMENTO']; 

     const valor = parseInt(object['REGISTROS'][prop]['VALOR']); 

     const nossoNumero = object['REGISTROS'][prop]['NOSSO_NUMERO']; 

     const numeroDocumento = object['REGISTROS'][prop]['NUMERO_DOCUMENTO']; 

     const codigoBanco = object['REGISTROS'][prop]['CODIGO_BANCO']; 

     const linhaDigitavel = object['REGISTROS'][prop]['LINHA_DIGITAVEL']; 

     const codigoBarras = object['REGISTROS'][prop]['CODIGO_BARRAS']; 

     oracledb.getConnection({ 
       user: "x", 
       password: "xxx", 
       connectString: "mycon/string" 
      }, 
      function(err, connection) { 
       if (err) { 
        console.error(err.message); 
        return; 
       } 

       connection.execute(
        "INSERT INTO USU_TBOLETO VALUES (:USU_CODIGO, :USU_ATEND, :USU_PAGAMENTO, " + 
        ":USU_VENCIMENTO, :USU_PROCESSA, :USU_VALOR, :USU_NOSSONUM, :NUMERODOC, :USU_CODBANCO, " + 
        ":USU_LINHADIG , :USU_CODBARRAS)", 

        [codigo, atendimento, pagamento, vencimento, processamento, valor, nossoNumero, 
         numeroDocumento, codigoBanco, linhaDigitavel, codigoBarras 
        ], { 
         autoCommit: true 
        }, 
        function(err, result) { 

         if (err) { 
          console.error(err.message); 
          doRelease(connection); 
          return; 
         } 
         console.log(codigo + ' - ' + atendimento + ' - ' + pagamento + ' - ' + vencimento); 
         ///console.log(result.metaData); 
         ///console.log(result.rows); 
         doRelease(connection); 
        }); 
      }); 
    } 


    function doRelease(connection) { 
     connection.release(
      function(err) { 
       if (err) { 
        console.error(err.message); 
       } 
      } 
     ); 
    } 
} 

En savoir plus sur la boucle et fermeture:

Javascript infamous Loop issue?

JavaScript closure inside loops – simple practical example

Asynchronous Process inside a javascript for loop

+0

Vous écrivez @abhishekkannoija J'étudierai les liens que vous avez indiqués pour moi. –