Wesley
Wesley

Reputation: 19

Query return as undefined using knex

I need to register a new user, when receiving the parameters make a query using the city name to get the state and city id (both are foreign keys). I implemented a function to find the ids. Inside the function using data.id the id is returned correctly. But at the time of insert in database is being inserted "undefined".

Apparently the save operation is being executed before the findCity and findState functions return the value.

execution flow

cidade = city, estado = city

module.exports = app => {
    const obterHash = (senha, callback) => {
        bcrypt.genSalt(10, (err, salt) => {
            bcrypt.hash(senha, salt, null, (err, hash) => callback(hash))
        })
    }
    var idCidade;
    var idEstado
    function findCidade(cidade, ) {
        app.db('cidades')
        .where({ nome: cidade })
        .first()
        .then(data => {
            idCidade = data.id
            console.log('inside findCity. data.id: '+data.id)
        }).catch((err) => console.log("erro cidade", err));
    return
    }

    function findEstado(uf) {
        app.db('estados')
        .where({ uf: uf })
        .first()
        .then(data => {
            idEstado = data.id
            console.log('inside findState. data.id: '+data.id)
        }).catch((err) => console.log("erro estado", err));
    }

    const save = (req, res) => {
        console.log("\n")
        findCidade(req.body.cidade)
        findEstado(req.body.uf)

        obterHash(req.body.senha, hash => {
            const senha = hash
            console.log("Will be inserted. idCity: "+idCidade+" idState: "+idEstado)
            app.db('salao')
                .insert({ idcidade: idCidade,
                          idestado: idEstado,
                          senha})
                .then(_ => res.status(200).send())
                .catch(err =>{res.status(400).json(err)})

        })
    }
    return { save }
}

I'm from Brazil and I'm using a translator, sorry for the spelling mistakes.

Upvotes: 0

Views: 1936

Answers (1)

MartenCatcher
MartenCatcher

Reputation: 2887

You are welcome to the asynchronous world!

General explanation: You are going to use results of a database querying before it will happen. Your program have to wait the results (idCidade, idEstado) before you can use it. Because of it you can find the record Will be inserted... first in your logs.

For the explanation I'm going to use Minimal Reproducible Example.

function findCidade(cidade) {
  return Promise.resolve(1);
}

function findEstado(uf) {
  return Promise.resolve(1);
}

Promise.all([findCidade(), findEstado()])
  .then((data) => console.log(data));

The output is:

[ 1, 1 ]

To solve the issue you have to:

  1. Return the promise explicitly with return statement.
  2. Await the results by async/await or Promise interface methods. Or use callbacks if it is more suitable to you.
module.exports = app => {
  const obterHash = (senha, callback) => {
    bcrypt.genSalt(10, (err, salt) => {
      bcrypt.hash(senha, salt, null, (err, hash) => callback(hash))
    })
  };

  function findCidade(cidade, ) {
    return app.db('cidades')
      .where({ nome: cidade })
      .first()
      .then(data => {
        idCidade = data.id
        console.log('inside findCity. data.id: '+data.id)
      }).catch((err) => console.log("erro cidade", err));
  }

  function findEstado(uf) {
    return app.db('estados')
      .where({ uf: uf })
      .first()
      .then(data => {
        idEstado = data.id
        console.log('inside findState. data.id: '+data.id)
      }).catch((err) => console.log("erro estado", err));
  }

  const save = (req, res) => {
    console.log("\n");

    Promise.all([findCidade(req.body.cidade), findEstado(req.body.uf)])
      .then((data) => {
        const [idCidade, idEstado] = data;
        obterHash(req.body.senha, hash => {
          const senha = hash;

          console.log("Will be inserted. idCity: "+idCidade+" idState: "+idEstado);
          app.db('salao')
            .insert({ idcidade: idCidade,
              idestado: idEstado,
              senha})
            .then(_ => res.status(200).send())
            .catch(err =>{res.status(400).json(err)})

        })
      })
      .catch((err) => console.log("general error", err));
  };
  return { save }
}

Upvotes: 1

Related Questions