Function is returning before SqlQuery finishes - javascript

I have a function that has a query that connects to a database and does a basic SELECT query, The query works fine, however the function appears to be returning before the query finishes all of its steps. In this case I have the Hello World Console log and the array is undefined. But if I setTimeout for one second and then log out the "NewArray" it has all the data from the query. So my question is: How do I return this data after the query has finished doing its magic.
async function getData() {
let newArray = []
let db = new sqlite3.Database('PATHTODB',sqlite3.OPEN_READWRITE, (err) => {
if (err) {
return console.error(err.message);
}
});
let selectQuery = `SELECT * FROM TableName;`
await db.all(
`${selectQuery}`,
(err, row) => {
console.log(row)
row.forEach(x => {
newArray.push(x)
})
}
)
console.log("Hello World", newArray)
return newArray
}
Tried using ASYNC/AWAIT

db.all(query, callback) is not an async function to await. It's just invoking it's callback asynchronously. Try promisfying it as follows;
async function getData() {
let newArray = []
let db = new sqlite3.Database('PATHTODB',sqlite3.OPEN_READWRITE, (err) => {
if (err) {
return console.error(err.message);
}
});
let selectQuery = `SELECT * FROM TableName;`,
row = await new Promise((resolve,reject) =>
db.all(`${selectQuery}`, (err,row) => err ? reject(err)
: resolve(row)));
console.log(row);
row.forEach(x => newArray.push(x));
console.log("Hello World", newArray);
return newArray
}

Related

ASYNC AWAIT function .find() mongodb

How can i save a variable from async function .find from mongodb? Inside the function console.log its working (prints the right value) and outside the function it is undefined.
var list;
MongoClient.connect(uri, function(err, db) {
var dbc = db.db("chat");
dbc.collection("chat_messages").find({user1: data.from, user2: data.to}).toArray(function (err, result){
console.log(result[0].msgs); <---- here its working
list = result[0].msgs;
});
db.close();
});
console.log(list); <---- here its not working
try work with Promises, look that sample:
const list = new Promise(function (resolve, reject) {
MongoClient.connect(uri, function(err, db) {
var dbc = db.db("chat");
dbc.collection("chat_messages").find({user1: data.from, user2: data.to}).toArray(function (err, result){
if(err) {
reject(err);
} else {
resolve(result);
}
db.close();
});
});
});
Then use as promise if you need:
list.then(arrayList => {
console.log(arrayList[0].msgs);
}).catch(err => console.log(err.message));
OR, force to run sync
const msgs = (await list)[0].msgs;
Here's how you would do it with async await.
async function getList() {
let db = await MongoClient.connect(url);
let dbo = db.db("testdb");
return await dbo.collection("cars").find({}, { projection: { _id: 0, name: 1} }).toArray()
}
listCars().then(cars => {
console.log(cars); //You will get your results here
})
The mongoDB queries in nodejs like the one above are asynchronous so you cannot get the return value in a variable directly. You either have to use a callback function or .then() to use promises like in the example above.
The toArray() function you are using is a MongoDB method, the one you mentioned in your question is a jQuery one. This is the correct documentation for your reference -> https://docs.mongodb.com/manual/reference/method/cursor.toArray/
You need to make the entire code block into an async-await code block, or take in the help of then block
let conn = await client.connect(url);
let db = conn.db("test");
const results = await db.collection("cars").find({}, { projection: { _id: 0, name: 1} }).toArray()
here results will have your output

variable initialisation node js

here's my problem in this function I'm trying to return an array of objects. When i do a console.log in the forEach loop as you can see the array is filled but when I try to print it juste before my return statement it's empty.
and here's my full js file :
const Discord = require("discord.js");
const Maths = require("../Utils/Maths");
const Stop = require("../Commands/stop");
const EventMitter = require("events");
const emitter = new EventMitter();
const fs = require("fs");
module.exports.play = async(client, channel, players) => {
players.push(client.guilds.cache.first().members.cache.array().filter(mem => mem.user.username === "user1").map(mem => mem.user)[0]);
players.push(client.guilds.cache.first().members.cache.array().filter(mem => mem.user.username === "users2").map(mem => mem.user)[0]);
try {
await beginMessage(players, channel);
let playersCards = await beginGame(client, players);
console.log(playersCards);
emitter.on("stop", async () => {
await channel.delete();
console.log("jeu fini");
});
}
catch(e) {
console.error(e);
}
};
async function beginMessage(players, channel) {
let message = "que le jeu commence ";
players.forEach(player => {
message += `${player.toString()} `;
});
await channel.send(message);
}
async function beginGame(client, players) {
let playersCards = [];
fs.readFile("Utils/cartes.json", 'utf8', async (err, data) => {
if(err) console.log(err);
let cartes = JSON.parse(data);
cartes = cartes.cartes;
players.forEach(async player => {
let playerCards = await distributeCards(player, cartes);
playersCards.push(playerCards);
//console.log(playersCards);
});
console.log(playersCards);
return playersCards;
});
}
async function distributeCards(player, cartes) {
let playerCards = [];
for(let i = 0; i < 4; i++) {
let carte = cartes[Maths.getRandomNumber(0,12)];
carte.count--;
playerCards.push(carte.name);
}
let dmChannel = await player.createDM();
await dmChannel.send(playerCards);
return playerCards;
}
module.exports.finishGame = function (client) {
emitter.emit("stop");
};
Must be a initialisation mistake or something like that I've been searching in my code but can't find it.
EDIT 3:
Since fs.readFile is not async we need to convert it to a promised based function something like below.
function readFile(path) {
return new Promise((resolve, reject) => {
fs.readFile(path, 'utf8', function (err, data) {
if (err) {
reject(err);
}
resolve(data);
});
});
}
I have updated the codesandbox snippet. Please check and see it that solves your issue.
https://codesandbox.io/s/nodejs-async-foreach-promise-v16w6
EDIT 2:
You need to implement custom forEach that will execute and return values as async. Something like this:
async function asyncForEach(array, callback) {
for (let index = 0; index < array.length; index++) {
await callback(array[index], index, array);
}
}
I have written a codesandbox snippet that might help you.
https://codesandbox.io/s/nodejs-async-foreach-promise-v16w6
EDIT:
Since you are using promise inside the forEach loop, the values are pushed
only after the promise is resolved. Since forEach is completes even before the values are pushed to playersCards you will not be able to see any values.
You can do something like this. I have updated the code. Haven't tested the code, but can help if there is issue.
async fs.readFile("Utils/cartes.json", 'utf8', async (err, data) => {
if(err) console.log(err);
let cartes = JSON.parse(data);
cartes = cartes.cartes;
await players.forEach(async player => {
let playerCardsPromiseValue = await distributeCards(player, cartes);
playersCards.push(playerCardsPromiseValue);
//console.log(playersCards);
});
console.log(playersCards);
return playersCards;
});

whats wrong with put rows into array sqlite3 nodejs

I want to save sqlite3 row values into an array. I followed what was discussed here:
Can't put rows into array using sqlite3 on Node.js
However when I console.log my would-be-array records, I obtain:
console.log(records) => an array with values [1,1,2]
console.log(records[1]) => undefined
There must be a mistake in my understanding of what's going on. What is wrong?
Full code below:
const sqlite3 = require('sqlite3').verbose();
let db = new sqlite3.Database('src/db/ksbib.db', (err) => { if (err) { return console.log(err.message); } });
let result = [];
let records = [];
function catchResult (err, row)
{
if (err) { return console.log(err.message); }
else { return result.push(row.objektid); }
}
function getData ()
{
return new Promise ((resolve, reject) =>
{
db.parallelize ( () =>
{
db.each(sqlTitel(param), catchResult);
db.each(sqlAutor(param), catchResult);
});
resolve(result);
})
}
async function res ()
{
records = await getData();
console.log(records);
console.log(records[1]);
return records;
};
let x = res();
console.log(x);
The contradiction between console.log(records) and console.log(records[1]) does not exist in the commandline. It seems that some other code interferes in the console.
Moreover, the promise as implemented above resolves with the emtpy result-array before the database request is finished. One can introduce a timeout to play with the code.
In order to resolve the promise after the database request, one should resolve it in the callback function of the request. That's also the reason why db.all is much easier to handle than db.each.
Instead of a series of database requests one can then use a series of promises. Thereby it is important to wait for every single promise to be resolved (just coupling them like this return await sqr(sqlTitle(y), []).then(sqr(sqlAuthor(y), [])) gives no unique result). The result-array is completed bit by bit.
const sqlite3 = require('sqlite3').verbose();
let db = new sqlite3.Database('ksbib.db', (err) => { if (err) { return console.log(err.message); } });
let result = [];
let p;
function sqr (sql, x)
{
return new Promise(function (resolve, reject)
{
db.all(sql, x, (err, rows) =>
{
if (err) {
reject(err);
} else {
rows.forEach( (row) => {result.push(row.objektid)} );
resolve(result);
}
});
});
}
( async () =>
{
p = await sqr(sqlTitle(y), []);
p = await sqr(sqlAuthor(y), []);
return p; //the final result
})();

Getting Return from an DB.ALL called

Trying to get the rows values from the DB all function. Unable to get that out of the DB.All function or pull it away from the arrow. The console log that I got will return the output I desire but I want it pull it out so I can use the JSON value.
Any idea how to do this?
handler: (request, h) => {
let sql = `SELECT TRIAL_ID as indexTrial, URL as urlImage FROM TRIAL`;
var test ='hi';
db.all(sql, (err, rows) => {
if (err) {
throw err;
}
test= JSON.stringify(rows);
console.log(test);
test =rows;
//return rows;
});
return test;
}
Needed a promise because it was going to fast to get the value
handler: (request, h) => {
let sql = `SELECT TRIAL_ID as indexTrial, URL as urlImage FROM TRIAL`;
var result =[];
var test ='hi';
return new Promise((resolve) => {
db.all(sql,[], (err, rows) => {
if (err) {
throw err;
}
resolve(rows);
})
}).then((rows) => {
return h.response(rows);
});

Function not returning pg-pool results

I'm trying to use pg-pool to query a Postgresql database. And then export this data to a Node.js express rest API.
Here's my exports function.
exports.getDashboard = function(req, response, next) {
let returnData = fetchData();
return response.status(200).json(returnData);
};
Which calls fetchData();
fetchData = async function() {
let returnData = [];
returnData.languages = await getLatestLanguages();
return returnData;
};
Which calls getLatestLanguages()
getLatestLanguages = function() {
pgPool.pool.query(
'SELECT * FROM "WordLanguage" ORDER BY id DESC LIMIT 30 ;',
(error, results) => {
if (error) {
throw error;
}
return results.rows;
}
);
}
If i place a console.log(results.rows) before getLatestLanguages() returns results.rows, then I get the data logged to the console.
However the object isn't being returned to fetchData. I tested this by logging the returnData to console before it is returned to exports.getDashboard();
I believe my problem is something to do with the async nature of pg-pool so I tried making my function async with an await but that didn't help.
What am I doing wrong?
you need getLatestLanguages to return a Promise, so you can await it from the caller
getLatestLanguages = function() {
return new Promise((resolve, reject) => {
pgPool.pool.query(
'SELECT * FROM "WordLanguage" ORDER BY id DESC LIMIT 30 ;',
(error, results) => {
if (error) {
reject(error);
}
resolve(results.rows);
}
);
})
}
you also need to await fetchData(), therefore getDashboard should be async
exports.getDashboard = async function(req, response, next) {
let returnData = await fetchData();
return response.status(200).json(returnData);
};
getLatestLanguages() should return a promise. For example
getLatestLanguages = function() {
return new Promise((resolve, reject) => {
pgPool.pool.query(
'SELECT * FROM "WordLanguage" ORDER BY id DESC LIMIT 30 ;',
(error, results) => {
if (error) {
reject(error);
}
resolve(results.rows);
}
);
});
};
fetchData() is async and therefore should be awaited
exports.getDashboard = async function(req, response, next) {
let returnData = await fetchData();
return response.status(200).json({ languages: returnData.languages });
};
Also make sure that you return returnData.languages in the correct format as above instead of ...json(returnData);

Categories

Resources