Doing Aysnc tasks in AWS Lambda inside map loop - javascript

I need to fetch user details from the database, where the user list is provided in an Array.
await userList.map(async (usr, index) => {
let sql = "SELECT `id`,`email`, `firstname`, `lastname` FROM `users` WHERE `id` = '"+usr.user_id+"'";
let user_info = await getData(sql,0);
userData.push(userObj);
});
Get Data function :-
let getData = async (sql, params) => {
return new Promise((resolve, reject) => {
pool.getConnection((err, connection) => {
if (err){
reject(err);
}
connection.query(sql, params, (err, results) => {
if (err){
reject(err);
}
connection.release();
resolve(results);
});
});
});
};
Now the problem is function is getting exited before the results are pulled from the database.
If I remove the loop & pull a single record everything is working fine.
But, i need to get data for all users.

Try this and let me know if it helps:
await Promise.all(userList.map(async (usr, index) => {
let sql = "SELECT `id`,`email`, `firstname`, `lastname` FROM `users` WHERE `id` = '"+usr.user_id+"'";
let user_info = await getData(sql,0);
userData.push(user_info);
}));

In this case you can avoid map and rather use a for loop to achieve the result.
You can try the below SO snippet, to see if this is the desired outcome you needed.
getData = (userId) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve("user"+ userId);
}, 500)
})
}
ids = [1,2,3];
//Final results
results = [];
async function getAllDataAsync(){
for(let i = 0; i < ids.length; i++ ){
let user_info = await getData(ids[i]);
results.push(user_info);
}
return Promise.resolve(results);
}
async function start(){
const res = await getAllDataAsync();
console.log(res);
console.log("Got the results. Put rest of the logic here");
}
start();
console.log("Function will exit first");

Related

Await sql and push to array before executing the result

I'm using mysql npm package to get data from the database.
My goal is to add every list(id) from lists Table and push it into lists array.
I'm getting the correct data from the database but when I result the query lists array is empty.
I think that I have to add async and await to the code to make it work. Tried in several places but I didn't make it work. Any idea what I'm doing wrong?
// GET - get all grocery_lists
Grocery_list.getAll = (result) => {
let lists = []; // <--- List Array
sql.query("SELECT id FROM lists", (err, res) => { // <--- Get all id from 'lists' table
if (err) {
console.log(err);
}
res.forEach(list => { // <--- Loop thru all lists
sql.query(`
SELECT items.id, items.name, items_x_lists.purchased
FROM items_x_lists
INNER JOIN items ON items_x_lists.itemId = items.id
WHERE items_x_lists.listId = ${list.id};
`, (err, res) => { // <--- Get all items for ${list.id} from 'items' table
if (err) {
console.log(err);
}
const list = {};
list.id = res.id;
console.log(list); // <--- { id: 1 } ... { id: 2 }
lists.push(list);
});
});
result(null, lists); // <--- returning empty array instead of [{ id: 1 }, { id: 2 }]
});
};
I think you can do it simply like this (not the exact code) but I think you've got the idea:
// GET - get all grocery_lists
Grocery_list.getAll = (result) => {
getData().then(data => {
// call result(data);
}).catch(err => {
// handle error for no data or any other errors
})
}
const getData = async () => {
try {
var res = await sql.query("SELECT id FROM lists");
// Handle error if no data found
if (!res) { Promise.reject("No data found"); }
} catch (error) {
return Promise.reject(error);
}
const listIds = res.map(id => id); // array of ids
try {
var data = await sql.query(`
SELECT items.id, items.name, items_x_lists.purchased
FROM items_x_lists
INNER JOIN items ON items_x_lists.itemId = items.id
WHERE items_x_lists.listId in ${listIds};`);
// Handle error if no data found
if (!data) { return Promise.reject("No data found") }
} catch (error) {
return Promise.reject(error);
}
return Promise.resolve(data)
}
this mighht be the solution
Grocery_list.getAll = async (result) => { return sql.query("SELECT id FROM lists", (err, res) => { // <--- Get all id from 'lists' table if (err) { console.log(err); } }); };
I’m outside, so I can only edit with my mobile phone. If the layout is strange, I apologize for it.
First of all, if it is me, I will adjust a few places
1.Create an async function and use Promise.all technology
async function queryAll(querys){
return await Promise.all(querys);
}
2.Create a Promise function to execute each sql
const queryPromise = id => {
return new Promise((resolve, reject) => {
sql.query(
'SELECT items.id, items.name, items_x_lists.purchased FROM items_x_lists INNER JOIN items ON items_x_lists.itemId = items.id WHERE items_x_lists.listId = ? ;',
id,
(err, rows, fields) => {
console.log(rows);
if (err) reject(err);
else resolve(rows);
}
);
});
};
3.Adjust the internal logic of the getAll event
const querys = []
res.forEach(list => {
querys.push(queryPromise(list.id));
});
const querysResults = await queryAll(querys);// remember to use async for function
querysResults.forEach(querysResult => {
lists.push({id:querysResult['id']});
});
Because there is no computer on hand, there may be some situations that need to be judged, but roughly this will work normally.
Hope this helps you :)

Passing multiple query objects with res.render

I want to pass multiple query objects with res.render() inside my route.js. I have a select.js which contains the SQL statements and delivers the objects to my route.js. This works fine until I want to pass multiple query objects with res.render().
Any ideas on how I can pass multiple objects at once?
snippet route.js (I need to pass get_PriceData here as well)
I already query get_KategorieData but I have no clue how to handle multiple queries in one route.
router.get('/edit', (req, res, next) => {
var speisenEintragenData = {};
db.get_KategorieData()
.then(({ data: kategorie_data }) => {
res.render('speiseEintragen', { kategorie_data }); //maybe putting res.render() after the db.get?
})
.catch((error) => {
console.log(error);
});
});
select.js
const db = require('./config');
//KATEGORIEN LADEN
const get_KategorieData=()=>{
var sql = 'SELECT * FROM Kategorie';
return new Promise((resolve,reject) => {
db.query(sql, function (err, data, fields) {
if (err) reject(err);
resolve({data});
});
})
}
//PREISE LADEN
const get_PriceData=()=>{
var sql = 'SELECT * FROM preise';
return new Promise((resolve,reject) => {
db.query(sql, function (err, data, fields) {
if (err) reject(err);
resolve({data});
});
})
}
module.exports={
get_KategorieData,
get_PriceData
}
There are two ways to go about this. One is to stick with promises and other is to use async/await.
Using promise
Create a new function to query database. This is if the module you are using does not support async/await and requires a callback.
const query = ( sql ) => {
return new Promise(( resolve, reject) => {
db.query(sql, function (err, data, fields) {
if (err) reject(err);
resolve(data);
});
})
}
// and then you can write an async/await function to call n queries like
const get_data = async () => {
const sql1 = '...';
const a = await query( sql1 );
const sql2 = '...';
const b = await query( sql2 );
....
....
....
const sqln = '...';
const n = await query( sqln );
return { a ,b,... ,n};
}
Or with async/await you can directly call db.query and use the response
const get_data = async () => {
const sql1 = '...';
const res_1 = await db.query(sql1);
const sql2 = '...';
const res_2 = await db.query(sql2);
return { a: res_1 ,b: res_2 };
}
router.js can rewritten as
router.get('/edit', async (req, res, next) => {
const {a:rename_a,b:rename_b and so on}=await db.get_data();
res.render('view', { rename_a,rename_b and so on })
});

node.js waiting for the db query results for the next step

I have a api code like below is written via node.js. Node.js is asynchronous so next step executing before db query result. In that time system had not got the data so gives an error. I have searched callback structure, promise and await but could not solve it. Thanks.
var dateTime = require("node-datetime");
var dt = dateTime.create();
module.exports = {
myOrderImportFromFileAPI: (req, res) => {
//let age = req.params.Age;
// send the player's details to the database
let userName = req.body.userName;
let companyID = req.body.companyId;
let channelId = req.body.channelId;
let orders = req.body.orders;
//default values
let orderTypeId = 1;
let orderStatusId = 1;
let createdDate = dt.format("Y-m-d H:M:S");
let getDate = dt.format("Y-m-d H:M:S");
db.query(`select ID,Code from operationcenters where CompanyID=${companyID}`, (err, result) => {
if (err) {
return res.status(500).send(err);
}
var operationCenterId = result[0].ID
result.find((e) => console.log(e.ID));
});
console.log("operationCenterId");
console.log(operationCenterId);
console.log("channelId");
console.log(channelId);
console.log(orders);
let query = "select ID value, Name label from channels"
db.query(query, (err, result) => {
if (err) {
return res.status(500).send(err);
}
res.send(`1`);
});
},
};
const dateTime = require("node-datetime");
const dt = dateTime.create();
const myOrderImportFromFileAPI = async (req, res) => {
const { userName, companyID, channelId, orders } = req.body
const orderTypeId = 1;
const orderStatusId = 1;
const createdDate = dt.format("Y-m-d H:M:S");
const getDate = dt.format("Y-m-d H:M:S");
try {
const queryData = await queryDatabase()
res.send(queryData).status(200)
} catch(error) {
res.send(error).status(500)
}
}
function queryDatabase() {
const query = "select ID value, Name label from channels"
return new Promise((resolve, reject) => {
db.query(query, (err, result) => {
if (err) {
reject(err)
}
resolve(result)
});
})
}
soomething like above will get you on the way. I haven't tested this so I can't say it works 100% but it is a good starting point. The reason for this is because by default the mysql db doesn't support asynchronous the modern way. That's why many people wrap in Bluebird(?) which is a library for creating promises which is a frequent dependency on drivers and such. So what you are doing is creating an async function with const myOrderImportFromFileAPI = async (req, res) => {}
After that then creating your variables, since you aren't redeclaring them then use const the first line after the function declaration is destructuring the object. Since we know the name of data and naming it as such then you can save lines with that and makes it more readible.
Finally, we wrap the async call in a try catch statement since we are calling a function which returns a promise(we don't need to call name async function queryDatabase since we are not performing anything asynchronous inside)
inside the actual function queryDatabase we will return with a resolved value of result or return a rejected value of err which will be caught in our try catch statment and will send the appropriate response..

Javascript function change variable value

I am currently developing signup page and I want to check if email address is already exist in the database.
var emailnum = email_num(`select * from contactinfo where email='${email}'`);
console.log(emailnum); //the output presents Promise { <pending> } not a num.
function sqlExecute(q) {
return new Promise((resolve, reject) => {
db.pool.query(q, function(err, result) {
if (err) {
console.log("ERROR ON " + q+"\n");
reject(err)
}
console.log("SUCCESS ON " + q);
resolve(result);
})
})
.catch(err => {
console.log(err);
})
}
//run check sql
async function email_num(tempquery){
var result = await sqlExecute(tempquery);
return result.rowCount;
}
I tried multiple ways but still could not figure it out.
I would appreciate any help TT
when I console.log, output is Always Promise { }.
I tried
var emailnum = email_num(`select count(*) as count from contactinfo where email='${email}'`)
.then((val)=>{
return val
};
console.log("number"+ emailnum);
The problem here is that you're not allowing the promise to resolve before attempting to retrieve the row count. When you create a function using async the return result is always going to be a promise. Here are a few solutions that will get you your desired result:
Solution 1: Use console.log to print the result of the promise after it has been resolved.
const email = 'something#gmail.com'
const numOfEmailsQuery = `SELECT * FROM contactinfo WHERE email = '${email}'`
email_num(numOfEmailsQuery)
.then(console.log)
.catch(console.error)
Solution 2: Use await inside of an async function to resolve the result of the promise and store it in a variable. Then print the result using console.log
async function printNumberOfEmails(email) {
const numOfEmailsQuery = `SELECT * FROM contactinfo WHERE email = '${email}'`
try {
const numOfEmails = await email_num(numOfEmailsQuery)
console.log(numOfEmails)
} catch (err) {
console.error(err)
}
}
const email = 'something#gmail.com'
printNumberOfEmails(email)
Hope that helps! Good luck!
First off, it's good practice to use prepared statements instead.
Also, you should just care about the count, so instead of select *, do select count(*) as count. Then you'll need check either the number of rows that result returned or the first index of rows, then the count property of that.
It should look something like this
function fetchEmailExists(email) {
const statement = 'select count(*) as count from contactinfo where email = $1';
return new Promise((resolve, reject) => {
db.pool.query(statement, [ email ], function(error, result) {
if (!error && result.rows.length > 0) {
resolve(result.rows[0]['count'] > 0);
} else {
reject(error);
}
});
})
.catch(error => {
console.log(error);
});
}
// Here is your call to fetchEmailExists
fetchEmailExists('test123#example.com')
.then(boolean => console.log(boolean));

Javascript get returned value of inside functions

I have the following function that gets a username and by making a query to mssql checks if already exists in databse. I want the checkForUsername() to return true if recordSet.recordset.length >= 1. How can I do that? I am a bit confused about async/await. Thanks.
function checkForUsername(UserIn) {
var dbConn = new sql.ConnectionPool(config);
dbConn.connect().then(function () {
var request = new sql.Request(dbConn);
request.query("SELECT * from Admins WHERE username='"+UserIn+"';").then(function (recordSet) {
console.log(recordSet.recordset.length);
if(recordSet.recordset.length >= 1)
//checkForUsername return true
dbConn.close();
}).catch(function (err) {
dbConn.close();
});
}).catch(function (err) {
console.log(err);
});
}
Of course I can't check if the following code works, but you can try rewriting your code for something like this:
const checkForUsername = async user => {
try {
const
dbConn = new sql.ConnectionPool(config),
sqlObj = await dbConn.connect(),
query = `SELECT * FROM Admins WHERE username='${user}';`, // Note that creating a query explicitly is not recommended as it is vulnerable to SQL injection attack!
recordSet = await new sqlObj.Request(dbConn)query(query),
hasRecords = !!recordSet.recordset.length;
return hasRecords;
} catch (error) {
console.log(error);
} finally {
dbConn.close();
}
}
// Call it
(async () => {
console.log(await checkForUsername('Jhon due');
})();
const checkForUsername = async UserIn => {
try {
var dbConn = new sql.ConnectionPool(config);
const sqlObj = await dbConn.connect();
const recordSet = await new sql.Request(dbConn).query(`SELECT * FROM Admins WHERE username='${UserIn}';`);
const hasRecords = !!recordSet.recordset.length;
return hasRecords;
}catch (error) {
console.log(error);
}finally{
dbConn.close();
}
}
// Call it
(async () => {
console.log(await checkForUsername('John'));
})();

Categories