Este es mi codigo, cuando imprimo en consola muestra []
var results = [];
connection.query("SELECT * FROM employees", (err, rows) => {
if (err) throw err;
results = rows;
});
console.log(results);
Este es mi codigo, cuando imprimo en consola muestra []
var results = [];
connection.query("SELECT * FROM employees", (err, rows) => {
if (err) throw err;
results = rows;
});
console.log(results);
PROBLEMA
El problema es de asincronía (y siempre lo es).
El método .query() de la librería mysql
tiene las siguientes firmas:
query(sqlString, callback)
query(sqlString, values, callback)
query(options, callback)
En las tres formas vemos que se usa una función callback
. (Relacionado: ¿Qué es un “callback”?). Y es que el proceso realizado por el método query()
es un proceso asíncrono.
Esto significa, que el motor de Javascript hace la llamada del proceso asíncrono y lo envía al loop
de eventos. Cuando el mismo retorne un resultado, se llamará a ejecución a la función pasada como callback
. Mientras esto sucede, se seguirán ejecutando las tareas que se encuentren después de la llamada al proceso asíncrono.
SOLUCIÓN
Lo que desees hacer con el resultado de la consulta, debes hacerlo dentro de tu función callback
. Ya que cuando la misma se ejecute el resultado ya estará disponible.
Veamos un ejemplo de lo que ocurre si tratamos de acceder a una variable cuyo valor se asigna dentro de un proceso asíncrono que usa una función callback
.
let resultado = [];
const miProcesoAsincrono = (str, cb) => {
console.log(str);
//simulación de proceso asíncrono con setTimeOut
setTimeout(() => {
// se asigna el valor de resultado y se pasa a la función callback
resultado.push('Algun valor');
cb(null, resultado);
}, 0);
}
miProcesoAsincrono('Inicia Proceso Asíncrono', (err, result) => {
if(err) throw err;
console.log('Proceso Asíncrono ha finalizado')
console.log(result);
});
console.log('Lo siguiente muestra un Array vacío:');
console.log(resultado);
Vemos claramente que el resultado se asigna dentro del proceso asíncrono, y el mismo no está disponible inmediatamente, por lo tanto la llamada a console.log()
que se hace después de llamar al proceso asíncrono devuelve el array
vacío.
Lo que debes hacer siempre que trabajes con procesos asíncronos, es escribir la lógica de tu programa (que dependa del resultado del proceso asíncrono), dentro de la función que pasas como callback
:
var results = [];
connection.query("SELECT * FROM employees", (err, rows) => {
if (err) throw err;
results = rows;
// aquí y sólo aquí puedes trabajar con el resultado
console.log(results);
});
Si deseas tener el resultado de tu consulta disponible fuera de la función callback
, tendrías que usar una función envoltorio que devuelva una Promesa, dado que la librería mysql
no trabaja con Promesas directamente. Para eso puedes leer esta respuesta, donde explico con detalle la forma de hacerlo.
Espero que esto aclare tu duda.
//Esta funcion recibe los datos para acceder a la base de datos
function getFromDB(mysql, host, database, user, password){
//Luego devuelve una function que conserva en su entorno lexico los datos para accesar
// y espera por el query, debe ser asincrona (async)
return async function(query){
//En esta variable se almacenara el resultado del query
let qResult;
//Crea la conexion
const connection = mysql.createConnection({
host: host,
database: database,
user: user,
password: password,
})
//Ejecuta la conexion
connection.connect(
error => {
if(error){
console.error(`Error connection ${error.stack}`);
return;
}
console.log(`Connected to ${database} as id: ${connection.threadId}`)
}
)
try{
//podemos usar await ya que estamos dentro de una funcion definida como
//asincrona 'async' para esperar el resultado de sendQuery y poder guardarlo
qResult = await sendQuery(query)
//Podemos pasarlo a JSON si lo necesitas
qResult = JSON.stringify(qResult, null, 2)
//esta es la promesa que envuelve el metodo .query()
//de este modo con el metodo resolve externamos el resultado
//y es almacenado en la variable qResult; arriba.
function sendQuery(query) {
return new Promise((resolve, reject) => {
connection.query(query, (error, results) => {
if(error){
reject(error)
}
resolve(results)
})
})
}
}catch(error){
console.error(error)
}finally{
connection.end()
}
//Arrojamos los resultados para ser almacenados en la constante data
return qResult
}
}
const fromDB = getFromDB(mysql, host, database, user, password)
let query = `SELECT productCode, productURL FROM products;`
const data = fromDB(query)