Solucionado (ver solução)
Solucionado
(ver solução)
10
respostas

Problema ao executar uma consulta em um laço de repetição no Node Mssql

Eu sei que alguns cursos mostrado aqui no alura é ensinado a utilização do modulo mysql.

Porém estou usando mssql (sql server) no node, e estou enfrentando um problema que acredito que seja haver com callback.

Para realizar consultar ao banco eu consigo norlmalmente, porém, quando tenho que realizar um laço de repetição em uma consulta ele não executa todos os index do arry,

exempo

valor [0,1,2],

é executado apenas o ultimo valor sem executar os outros. meu controller

var itensParaEnvio =  []; 

 api.contabilizacaoItems =  function (req, res, next) {
        itensParaEnvio = [];
        var dados = req.body;
        cont = 1
        console.log(dados.items.length);
        dados.items.forEach(function (item, key){ 
            item.aprovacao = dados.aprovacao
            solicitacaoSqlDAO.contabilizacaoItem(item, function (erro, recordset) {
               item.contItem= recordset.recordset;
               solicitacaoSqlDAO.aenItem(item, function (erro, recordset) {
                   item.aenItens= recordset.recordset;
                   itensParaEnvio[key]= item;
                   if(cont == dados.items.length) res.status(200).json(itensParaEnvio);
                   else res.status(404).json("erro");
               })
           })
        });  
    };

    return api;
}

meu DAO

solicitacaoDAO.prototype.contabilizacaoItem = function (item, callback) {
  console.log("# PARA CONSULTA contabilizacaoItem# ");
  mssql.close();
  mssql.connect(this._connection, function (err) {
    if (err) {
      console.log("# ERRO AO REALIZAR CONEXAO PARA CONSULTA contabilizacaoItem# "+ err);
    }
    var request = new mssql.Request();
    query = "alguma consulta";
    // console.log(query);
    request.query(query, function (err, recordset) {
      if (err) {
        console.log(query);
        callback(err,recordset);
      } else {
        callback(err,recordset);
      }   
    });
  });
}



solicitacaoDAO.prototype.aenItem = function (item, callback) {
  console.log("# PARA CONSULTA aenItem# ");

  mssql.close();
  mssql.connect(this._connection, function (err) {
    if (err) {
      console.log("# ERRO AO REALIZAR CONEXAO PARA CONSULTA aenItem# "+ err);
    }

    var request = new mssql.Request();
    query = "alguma consulta";
    // console.log(query);
    request.query(query, function (err, recordset) {
      if (err) {
        console.log(query);
        callback(err,recordset);
      } else {
        callback(err,recordset);
      }   
    });
  });
}

Alguém já usou mssql ? ou já passou por alguma situação parecida ?

desde já agradeço!

10 respostas

Oi Ciro, só pra mim ter certeza que entendi, no MSSQL você tem vários registros, mas o laço só mostra o último, é isso mesmo?

na verdade, é que é pra acontecer mais de uma consulta no laço, ou seja é pra retornar por exemplo 3 resultados diferentes, porém apenas o ultimo resultada aparece.

Tem uma coisa no seu código que eu não entendo, por que você sempre fecha a conexão antes de abrir, sendo que o comum é abrir e depois fechar?

Estou achando também que o trecho de código que colocou aqui é insuficiente pra gente trackear o problema. Algumas coisas não estão claras ai. Pode descrever as entradas e o processo?

Algo que eu não vi no código foi onde incrementa a variavel "cont". Pelo código, ele faz um loop onde para cada item se faz mais duas consultas, e quando a variavel contador for igual ao conteudo de resultados do Loop se retorna um JSON com os resultados.

Eu colocaria algumas mensagens no console para entender melhor onde está falhando.

Uma sugestão seria a seguinte:

var itensParaEnvio =  []; 

 api.contabilizacaoItems =  function (req, res, next) {
        itensParaEnvio = [];
        var dados = req.body;
        cont = 1
        console.log(dados.items.length);
        console.log('cont e igual a 1');
        dados.items.forEach(function (item, key){ 
            console.log('executando o loop');

            item.aprovacao = dados.aprovacao
            solicitacaoSqlDAO.contabilizacaoItem(item, function (erro, recordset) {
                if (erro) {
                    console.log('erro consulta 1');
                    return;
                }
               console.log('sucesso consulta 1');
               item.contItem= recordset.recordset;
               solicitacaoSqlDAO.aenItem(item, function (erro, recordset) {
                    if (erro) {
                        console.log('erro consulta 2');
                        return;
                    }
                    console.log('sucesso consulta 2');
                    console.log('o valor atual de cont e ' + cont);
                   item.aenItens= recordset.recordset;
                   itensParaEnvio[key]= item;
                   if(cont == dados.items.length) res.status(200).json(itensParaEnvio);
                   else res.status(404).json("erro");
               })
           })
        });  
    };

    return api;
}

Eu criei o acesso a banco com sql server assim. dbConfig.js

function Config(){
    return  {
        user: 'sa',
        password: 'sa123',
        server: 'AA-PC\\SQLEXPRESS', // You can use 'localhost\\instance' to connect to named instance 
        database: 'aluranode',
    }
}

module.exports = function(){
    return Config;
}

produtoDB.js

module.exports = function(app){
    const sql = require('mssql');
    this.lista = function(){


        return sql.connect(app.infra.dbConnection())
        .then(() => {
            return sql.query`select * from livro`
        }).then(result => {
            sql.close();
            return result.recordset;
        }).catch(err => {
            // ... error checks 
            sql.close();
        });
    }
}

produtoRoute.js Aqui eu realmente efetivo a consulta, o select no banco

module.exports = function(app){
    app.get('/produtos',function(req,res){
        new app.infra.produtoDB.lista().then(result=>{
            res.render('produtos/lista', {lista:result});    
        }); 
    });    
}

Kleber,

estou tentando realizar o que voce deu como exemplo, porém não estou conseguindo

meu arquivo de config

configSqlDAO2.js

function Config(){
    return  {
        user: 'admin',
        password: 'gr@',
        server: '187.94.62.70',
        database: 'teste',
        port: '14330'
    }
}

module.exports = function(){
    return Config;
}

meu dao

aproveDB.js

module.exports = function (app) {

    const sql = require('mssql');

    this.lista = function(aprovacao){
        return sql.connect(app.config.configSqlDAO2())
        .then(() => {
            var query = "select * from AD_MESTRE WHERE NUM_AD = '"+aprovacao.NUM_AD+"' AND COD_EMPRESA_ORIG = (select DISTINCT EMPRESA_MATRIZ from LOG_EMPRESA_COMPL WHERE EMPRESA = '"+aprovacao.COD_EMPRESA_ORIG+"' ) AND NUM_AD IN (SELECT NUM_AD FROM LOGIX.AD_ITEM WHERE LOGIX.AD_MESTRE.COD_EMPRESA  = LOGIX.AD_ITEM.COD_EMPRESA)"
            return mssql.query+query;
        }).then(result => {
            sql.close();
            return result.recordset;
        }).catch(err => {
            sql.close();
        });
    }

}

e minha api onde fica a chamado do DAO

     new app.DAO.aproveDB.lista(recordset.recordset[i]).then(result=>{
                            console.log(result); 
     });

porém acontece esse err

Cannot read property 'lista' of undefined

Como esse aproveDB está sendo carregado? Ele não está presente no DAO não pra dar esse erro

Oi wanderson , sim ele está presente no DAO, na verdade foi a primeira coisa que pensei.

ele ta no diretorio DAO, existe outros que funcionam mas não como o exemplo Kleber.

solução!

Ciro, o erro diz que Cannot read property 'lista' of undefined ele não consegue ler a função lista de undefined, então o atributo aproveDB não existe ou não está sendo carregado completamente.

Lembrando que você tá usando ali, this.lista, o problema pode estar ali, o lista ao meu ver está sendo exportado como atributo do objeto exports.

opa era exatamente isso, vlwwww