Javascript function change variable value - javascript

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));

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 :)

JavaScript, Node.JS : unable to update a variable in a loop

I am building an API via Node.js.
I have a loop that add values to an initially empty array, but the array stays empty. The following is my code.
get_doc_name = async (event) => {
const connection = await db.connection()
try {
const doc_ids = event.doc_ids
// array that has JSONs as element
// e.g. [ {1 : 'certificate.pdf'}, {2: 'report.jpeg'}]
let dict = []
await doc_ids.map(async function(id) {
const sql = "SELECT link FROM document WHERE id=?"
await connection.query(sql, id, async function (err, result) {
if (err) throw err
const link = await result[0].link
const doc_name = await link.split('/').pop()
await dict.push({
key: id,
value: doc_name
})
console.log(dict)
})
})
return dict
} catch (err) {
console.log(err.message)
} finally {
connection.end()
console.log('MySQL connection closed')
}
}
The function returns an empty array. However, it prints the updated array when console.log(dict) is executed. I need the function to return the updated array.
Moreover, when the function is called, the codes in the 'finally' statement are executed before the codes in 'try' statement. The program prints MySQL connection closed before it prints dict.
Any help is highly appreciated!
As you are retrieving data from DB, it is better to use serial Promise instead of parallel Promises to get data from DB. The way I do is in serial Promise.
It is a better practice to get data with SELECT link FROM document WHERE id in () instead of id= in your SQL because you don't need to make multiple I/O to the DB in your case.
However, I didn't change this part of logic.
Also, you should promisefy your connection.query and return a value from it.
I make it in a getResult() function.
get_doc_name = async event => {
try {
const connection = await db.connection();
try {
const doc_ids = event.doc_ids;
// array that has JSONs as element
// e.g. [ {1 : 'certificate.pdf'}, {2: 'report.jpeg'}]
let dict = [];
//Promises in serial here
for (const id of doc_ids) {
const result = await getResult(connection, id);
dict.push(result);
}
console.log(dict);
return dict;
} catch (err) {
console.log(err);
} finally {
await connection.end();
console.log("MySQL connection closed");
}
} catch (err) {
console.log(err);
}
};
function getResult(connection, id) {
return new Promise((resolve, reject) => {
const sql = "SELECT link FROM document WHERE id=?";
connection.query(sql, id, function (err, result) {
if (err) reject(err);
const link = result[0].link;
const doc_name = link.split("/").pop();
resolve({ key: id, value: doc_name });
});
});
}
get_doc_name()
.then(dict => console.log(dict))
.catch(console.log);

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..

Values coming back as 'undefined' in for loop inside ES6 promise

So I'm currently writing an inventory application, and I'm running into some issues inserting values into my database. What happens is that I get a list of item objects that contain information about that specific item. I then push those items into a list and call a socket which runs a for loop to insert those items into my database, but when I look at the table where these items should be, all of their values are set as undefined.
My item object looks something like this:
let ItemObject = {
ID: id,
Name: name,
Qty: qty
}
The promise that calls the DB sequence:
export const insertItem = async (list) => {
return new Promise(async (resolve, reject) => {
try {
console.log(list);
for(let i = 0; i < list.length; i++){
const writeSolutionData = `INSERT INTO database (ID, Name, Qty) VALUES ("${list.ID}", "${list.Name}", "${list.Qty});`;
const response = await db(writeSolutionData, "Inserting Item");
resolve(response);
}
} catch (e) {
console.log("ERROR database.insertItem: " + e);
reject(e);
}
});
};
This is the socket that gets called:
socket.on('insertItem', async (data, callback) => {
try {
const results = await insertItem(data);
callback(true);
}
catch (error) {
callback(false);
}
});
When I console log the list before the for loop, I get what I would expect the output to be, but after this promise finishes the data that's returned in my DB is undefined. I also receive no errors from the callback either. The idea of ES6 promises are still new to me, so forgive me if what I have here is not correct. This is the first time I've tried implementing a for loop within an asynchronous promise like this, so it was no surprise to me that this didn't work the first time around.
If anyone has any suggestions as to what I'm doing wrong, I would greatly appreciate it. Thanks!
The insertItem does not have to be an async function. Just return the Promise and use async it the promise callback, only in that scope the await keyword is needed.
An async function automatically returns a Promise, but you need a Promise constructor to use the resolve and reject methods. It is basically the same thing but with different syntax and options.
Also I've noticed that your loop has an error. You try to select list.ID, list.Name and list.Qty from the array, but instead should get the values from the items in the array.
I also found a missing " at the end of your query string.
export const insertItem = (list) => new Promise(async (resolve, reject) => {
try {
list.forEach(item => {
const writeSolutionData = `INSERT INTO database (ID, Name, Qty) VALUES ("${item.ID}", "${item.Name}", "${item.Qty}");`;
const response = await db(writeSolutionData, "Inserting Item");
resolve(response);
});
} catch (e) {
console.log("ERROR database.insertItem: " + e);
reject(e);
}
});
Addendum
Updated the answer with usage of Promise.all. Suggested by #wizloc.
This will loop all of your items and return promises from the db() function and stores them into a new array. Promise.all will then resolve whenever all of the promises in the array have fullfilled and return the values of each promise in a single array.
export const insertItem = (list) => new Promise(async (resolve, reject) => {
try {
const responses = list.map(item => {
const writeSolutionData = `INSERT INTO database (ID, Name, Qty) VALUES ("${item.ID}", "${item.Name}", "${item.Qty}");`;
return db(writeSolutionData, "Inserting Item");
});
const results = await Promise.all(responses);
resolve(results);
} catch (e) {
console.log("ERROR database.insertItem: " + e);
reject(e);
}
});
I'm unfamiliar with what
const writeSolutionData = `INSERT INTO database (ID, Name, Qty) VALUES ("${list.ID}", "${list.Name}", "${list.Qty}");`;
const response = await db(writeSolutionData, "Inserting Item");
actually does (aside from the obvious), but since db(writeSolutionData, "Inserting Item") is awaitable, it returns a promise. As I mentioned in comments, your original code is resolving in the first iteration of the loop, therefore if you need to access the values returned from your promises down the road, you will find you only have access to the first value. You asked why you would need the values since you can just query for them afterwards, I can't answer this since I don't know anything about your project, what you plan to do with the data after it is inserted, etc. But another benefit of promises is error handling by chaining .then() and .catch().
You could simplify your entire insertData method to the following
socket.on('insertItem', async (data, callback) => {
const promises = data.map(x =>
db(`INSERT INTO database (ID, Name, Qty) VALUES ("${x.ID}", "${x.Name}", "${x.Qty});`)
)
Promise.all(promises)
.then(values => {
// Do something with values array
callback(true)
})
.catch(error => {
// Error handling
callback(false)
})
});
Doing it this way will ensure callback(true) is only called if all items were inserted successfully, and will error (callback(false)) if any of the items failed.
I think insertItem is not an async function because it doesn't contain await...
export const insertItem = /*async <- remove it */ (list) => {
return new Promise(async (resolve, reject) => {
try {
console.log(list);
for(let i = 0; i < list.length; i++){
const writeSolutionData = `INSERT INTO database (ID, Name, Qty) VALUES ("${list.ID}", "${list.Name}", "${list.Qty});`;
const response = await db(writeSolutionData, "Inserting Item");
resolve(response);
}
} catch (e) {
console.log("ERROR database.insertItem: " + e);
reject(e);
}
});
};

javascript promise after foreach loop with multiple mongoose find

I'm trying to have a loop with some db calls, and once their all done ill send the result. - Using a promise, but if i have my promise after the callback it dosent work.
let notuser = [];
let promise = new Promise((resolve, reject) => {
users.forEach((x) => {
User.find({
/* query here */
}, function(err, results) {
if(err) throw err
if(results.length) {
notuser.push(x);
/* resolve(notuser) works here - but were not done yet*/
}
})
});
resolve(notuser); /*not giving me the array */
}).then((notuser) => {
return res.json(notuser)
})
how can i handle this ?
Below is a function called findManyUsers which does what you're looking for. Mongo find will return a promise to you, so just collect those promises in a loop and run them together with Promise.all(). So you can see it in action, I've added a mock User class with a promise-returning find method...
// User class pretends to be the mongo user. The find() method
// returns a promise to 'find" a user with a given id
class User {
static find(id) {
return new Promise(r => {
setTimeout(() => r({ id: `user-${id}` }), 500);
});
}
}
// return a promise to find all of the users with the given ids
async function findManyUsers(ids) {
let promises = ids.map(id => User.find(id));
return Promise.all(promises);
}
findManyUsers(['A', 'B', 'C']).then(result => console.log(result));
I suggest you take a look at async it's a great library for this sort of things and more, I really think you should get used to implement it.
I would solve your problem using the following
const async = require('async')
let notuser = [];
async.forEach(users, (user, callback)=>{
User.find({}, (err, results) => {
if (err) callback(err)
if(results.length) {
notUser.push(x)
callback(null)
}
})
}, (err) => {
err ? throw err : return(notuser)
})
However, if you don't want to use a 3rd party library, you are better off using promise.all and await for it to finish.
EDIT: Remember to install async using npm or yarn something similar to yarn add async -- npm install async
I used #danh solution for the basis of fixing in my scenario (so credit goes there), but thought my code may be relevant to someone else, looking to use standard mongoose without async. I want to gets a summary of how many reports for a certain status and return the last 5 for each, combined into one response.
const { Report } = require('../../models/report');
const Workspace = require('../../models/workspace');
// GET request to return page of items from users report
module.exports = (req, res, next) => {
const workspaceId = req.params.workspaceId || req.workspaceId;
let summary = [];
// returns a mongoose like promise
function addStatusSummary(status) {
let totalItems;
let $regex = `^${status}$`;
let query = {
$and: [{ workspace: workspaceId }, { status: { $regex, $options: 'i' } }],
};
return Report.find(query)
.countDocuments()
.then((numberOfItems) => {
totalItems = numberOfItems;
return Report.find(query)
.sort({ updatedAt: -1 })
.skip(0)
.limit(5);
})
.then((reports) => {
const items = reports.map((r) => r.displayForMember());
summary.push({
status,
items,
totalItems,
});
})
.catch((err) => {
if (!err.statusCode) {
err.statusCode = 500;
}
next(err);
});
}
Workspace.findById(workspaceId)
.then((workspace) => {
let promises = workspace.custom.statusList.map((status) =>
addStatusSummary(status)
);
return Promise.all(promises);
})
.then(() => {
res.status(200).json({
summary,
});
})
.catch((err) => {
if (!err.statusCode) {
err.statusCode = 500;
}
next(err);
});
};

Categories