Mysql node function - javascript

I want to make a call to the mysql server with node and store data into a fucntion:
async function getData(uri){
let data = await esisteMysql(uri);
console.log(data);
}
function esisteMysql(uri) {
connection.query(`select * from data where url = '${uri}'`, function (error, row) {
if(error) throw error;
else {
if(row && row.length){
console.log('FOUND');
//console.log(row);
return row;
}else{
console.log('NOT FOUND');
return row = null;
}
}
})
}
It doesn't work, it returns an undefined. I can log data only if I print it in esisteMysql with console.log(row);

Your esisteMysql() needs to produce a promise in order to work with await. It might look something like:
async function getData(uri) {
let data = await esisteMysql(uri);
console.log(data);
}
function esisteMysql(uri) {
return new Promise(function(resolve, reject) {
connection.query(`select * from data where url = '${uri}'`, function (error, row) {
if (error) {
reject(error);
} else {
resolve(row);
}
})
}
}
See https://javascript.info/async for more.

Related

TypeError: query.findAll is not a function node js mysql

i am trying to pass the sql query parameters to data access js file. i have imported the function in current file, but still am getting the below error.
current file
const tcount = async (value) => {
const sql = 'trainingcount';
const result = await query.findAll(sql);
return result;
}
data access file
const query = (results) => {
findAll: async (sql, result) => {
connection.query(`SELECT * FROM trainingcount`, (err, rows) => {
if (err) {
return results(null, err);
} else {
return results(rows);
}
});
};
};
export { query };
(node:11132) UnhandledPromiseRejectionWarning: TypeError:
query.findAll is not a function
EDIT: Check #rid solutions on the comments for the specific problem of calling the proper function. My answer solves a different problem in OP code.
you call return inside the callback function, so you are returning THAT function, not findAll. You need to return a Promise:
const query = (results) => {
findAll: (sql, result) => {
return new Promise((resolve, reject) => {
connection.query(`SELECT * FROM trainingcount`, (err, rows) => {
if (err) {
reject(err);
} else {
resolve(rows);
}
});
});
};
};
export { query };

NodeJS + ExpressJS: How to wait for forEach to finish with SQL queries inside

I'm trying to wait for a forEach to finish, and the forEach loop has two nested requests inside.
I need to wait untill the forEach finish beacuse I fill an array with the queries results and then, when the forEach is finish, then call another function, but I cannot do it well because sometimes, the array is fully filled, but othertimes the array is incomplete.
Here is my code:
readAllClientsAndInvoices: function(request, response) {
let clientsInvoices = [];
DAOClients.readAllClientesById(request.session.id, function (err, clients) {
if (err) {
console.log(err);
} else {
clients.forEach(function (client, idx, array) {
DAOClients.readClientDataById(client.id, function (err, data) {
if (err) {
console.log(err)
} else {
DAOClients.readAllclientInvoices(data.id, function (err, invoices) {
if (err) {
console.log(err);
} else {
let pair = {
clientData: data,
invoicesList: invoices
};
clientsInvoices.push(pair);
}
});
}
if (idx === array.length - 1) {
DAOClients.createClientPDFReportWOCommentsV2(clientsInvoices, function (err, res) {
if (err) {
console.log(err);
} else {
response.redirect(307, '/client/searchClient');
}
});
}
});
});
}
});
}
This is how I do it now, but I need to wait untill the array is fully filled with all the clients and its invoices and then call to createclientPDFReportWOCommentsV2 function but I don't know how to do it.
Thanks everyone
You can try to use a map instead of forEach in order to accept a return value from every call of the callback function, that return value will have to be a Promise, resolving after particular call has been completed. Since I don't see any particular error handling in your example I just made it so that in case of error Promise resolves undefined which is filtered afterwards in the createClientPDFReportWOCommentsV2 call.
function readAllClientsAndInvoices(request, response) {
DAOClients.readAllClientesById(request.session.id, function (err, clients) {
if (err) return console.log(err);
Promise.all(clients.map(client => {
return new Promise(resolve => {
DAOClients.readClientDataById(client.id, function (err, data) {
if (err) {
console.log(err)
resolve();
} else {
DAOClients.readAllclientInvoices(data.id, function (err, invoices) {
if (err) {
console.log(err);
resolve();
} else {
let pair = {
clientData: data,
invoicesList: invoices
};
resolve(pair);
}
});
}
});
});
})).then(clientsInvoices => {
DAOClients.createClientPDFReportWOCommentsV2(clientsInvoices.filter(Boolean), function (err, res) {
if (err) {
console.log(err);
} else {
response.redirect(307, '/client/searchClient');
}
});
});
});
}
To solve these problems i would use Async/Await https://javascript.info/async-await. Make sure all the methods you're calling on DAOClients returns a Promise https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
For example
function readAllClientesById() {
return new Promise((resolve, reject) => {
// Wait for some data to get fetched from SQL
// and call resolve instead of callback function
resolve(data)
// Or of there was an error
reject(err)
})
}
This is natively supported in the latest versions of Node.js.
Example of Async/Await if promises is implemented:
async function readAllClientsAndInvoices(req, res) {
try {
const clientInvoices = []
const clients = await DAOClients.readAllClientesById(req.session.id)
for (const client of clients) {
const clientData = await DAOClients.readClientDataById(client.id)
const clientInvoices = await DAOClients.readAllclientInvoices(clientData.id)
clientInvoices.push({
clientData: data,
invoicesList: invoices
})
}
// This code won't be executed until the for loop is completed
await DAOClients.createClientPDFReportWOCommentsV2(clientInvoices)
} catch (err) {
return res.status(err.code).send(err)
}
res.redirect(307, '/client/searchClient');
}
I haven't tested the code, it's just an example of how I approach these type of problems.

How to use async/await to get data from sqlite db.each

I would like to get my data out from the sqlite db.each function using the promise object and the async/await I tried to do it but I don't really understand how to do it and I would like some explanations
my code below :
var sqlite3 = require('sqlite3').verbose();
var db = new sqlite3.Database('./data.sqlite', (err) => {
if (err) {
console.error(err.message);
}
console.log('Connected to the database');
});
function request (req) {
new Promise(function (resolve, reject) {
db.each(req, function (err, row) {
if (err)
reject(err);
else
data.push(row);
}, function (err, n) {
if (err) {
reject(err);
}
else
resolve(data);
});
});
}
data = await request("select * from user "); //I'm getting errors here
db.close((err) => {
if (err) {
return console.error(err.message);
}
console.log('Close the database connection');
});
await can only be used inside an async function. Create an async function, inside this function, await the promise returned by request function
async function makeRequest() {
data = await request("select * from user ");
}
and you need to return the promise from request function so that it can be awaited
function request (req) {
return new Promise(function (resolve, reject) {
// code
});
}

how to run mongoose method inside for loop, as mongoose function is asynchronous

I am trying to run an mongoose find command and if it matches few dataset in array, then need to update the database.
here is the query i have written.
membersId=["U-ZCIwZGvW", "U-MbyAVxXf", "U-Gbe9RhGu"];
let updateUserData=(groupData)=>{
return new Promise((resolve,reject)=>{
for(M in membersId){
console.log(membersId[M]);
UserModel.findOne({userId:membersId[M]},(err,response)=>{
if(err){
console.log(err);
reject(err);
}else if(check.isEmpty(response)){
reject("Id not found");
}else{
if(!response.groups.includes(groupData._id)){
response.groups.push(groupData._id)
response.save((err,data)=>{
if(err){
console.log(err);
reject(err);
}else{
console.log(data);
}
})
}
}
})
}
resolve(groupData,'Members Added','AddMembersToGroup',00);
})
}
i read about async-await and tried this..
membersId=["U-ZCIwZGvW", "U-MbyAVxXf", "U-Gbe9RhGu"];
let updateUserData = (groupData) => {
return new Promise((resolve, reject) => {
async function getTodos() {
for (const M of membersId) {
await UserModel.findOne({ userId: M }, (err, response) => {
if (err) {
console.log(err);
reject(err);
} else if (check.isEmpty(response)) {
reject("Id not found");
} else {
if (!response.groups.includes(groupData._id)) {
response.groups.push(groupData._id)
response.save((err, data) => {
if (err) {
console.log(err);
reject(err);
} else {
console.log(data);
}
})
}
}
})
}
console.log('Finished!');
resolve(groupData,'Members Added','AddMembersToGroup',00);
}
getTodos();
})
}
the async method is working, but still it is not fully synchronous, and also if any error occurs, it does not stop.
how to exit the for loop on error and do the resolve statement only once so that it does not go back to other code once run.
even if there is error it runs.
There are a few things :
you don't need to perform multiple find requests to find & update multiple records, just use updateMany with the right filter & update parameters
an async function return a Promise which is not the case of your function getTodos
you need to invoke the async function like this : await getTodos();
in case your promise rejects something you need to handle this in try/catch (error is thrown)
You can use the following inside an async function :
try {
var response = await getTodos(groupData, membersId);
console.log(response);
}
catch(err){
console.log(err);
}
with the getTodos function :
async function getTodos(groupData,membersId) {
return new Promise(function(resolve, reject){
UserModel.updateMany({
userId: { "$in" : membersId},
groups: { "$ne": groupData._id }
},{
$push: { groups: groupData._id }
}, function(err,response){
if (err) {
reject(err);
} else if (response.nModified === 0){
reject("Id not found");
} else {
resolve(response.nModified + " items modified");
}
});
});
}

Recursively calling asynchronous function that returns a promise

I'm trying to recursively call AWS's SNS listEndpointsByPlatformApplication. This returns the first 100 endpoints then a token in NextToken if there are more to return (details: AWS SNS listEndpointsByPlatformApplication).
Here's what I've tried:
var getEndpoints = function(platformARN, token) {
return new models.sequelize.Promise(function(resolve, reject) {
var params = {
PlatformApplicationArn: platformARNDev
};
if (token != null) {
params['NextToken'] = token;
}
sns.listEndpointsByPlatformApplication(params, function(err, data) {
if (err) {
return reject(err);
}
else {
endpoints = endpoints.concat(data.Endpoints); //save to global var
if ('NextToken' in data) {
//call recursively
return getEndpoints(platformARN, data.NextToken);
}
else {
console.log('trying to break out!');
return resolve(true);
}
}
});
});
}
I'm calling it with:
getEndpoints(platformARNDev, null)
.then(function(ret) {
console.log('HERE!');
}, function(err) {
console.log(err);
});
Problem is: the first call happens, then the recursive call happens, and I get the message trying to break out! but the HERE! never gets called. I've got something wrong with how my promises are returning I think.
Grateful for pointers.
The problem is that you try and resolve/reject partially completed query. Here is a complete working example with dummy service. I incapsulated the data grabbing into it's own recursive function and only do resolve/reject when i've completely fetched all the data or stumbled upon an error:
// This is the mock of the service. It yields data and token if
// it has more data to show. Otherwise data and null as a token.
var dummyData = [0, 1, 2, 3, 4];
function dummyAsyncCall(token, callback) {
token = token || 0;
setTimeout(function() {
callback({
dummyDataPart: dummyData[token],
token: (typeof (dummyData[token]) == 'undefined') ? null : (token + 1)
});
});
}
// Here is how you would recursively call it with promises:
function getAllData() {
//data accumulator is sitting within the function so it doesn't pollute the global namespace.
var dataSoFar = [];
function recursiveCall(token, resolve, reject) {
dummyAsyncCall(token, function(data) {
if (data.error) {
reject(data.error);
}
if (!data.token) {
//You don't need to return the resolve/reject result.
resolve(dataSoFar);
} else {
dataSoFar = dataSoFar.concat(data.dummyDataPart);
recursiveCall(data.token, resolve, reject);
}
});
}
return new Promise(function(resolve, reject) {
// Note me passing resolve and reject into the recursive call.
// I like it this way but you can just store them within the closure for
// later use
recursiveCall(null, resolve, reject);
});
}
//Here is the call to the recursive service.
getAllData().then(function(data) {
console.log(data);
});
Fiddle with me
That's because you dont need to return resolve/reject, just call resolve/reject when the recursive call completes. A rough code would look like this
var getEndpoints = function(platformARN, token) {
return new models.sequelize.Promise(function(resolve, reject) {
var params = {
PlatformApplicationArn: platformARNDev
};
if (token != null) {
params['NextToken'] = token;
}
sns.listEndpointsByPlatformApplication(params, function(err, data) {
if (err) {
reject(err);
}
else {
endpoints = endpoints.concat(data.Endpoints); //save to global var
if ('NextToken' in data) {
//call recursively
getEndpoints(platformARN, data.NextToken).then(function () {
resolve(true);
}).catch(function (err) {
reject(err);
});
}
else {
console.log('trying to break out!');
resolve(true);
}
}
});
});
}
(caution: this is just a rough code, may work or may not, but is to give a general idea)
I've added a code snippet below, to support this concept, and it works great, check it out.
i = 0;
$('#output').empty();
function pro() {
return new Promise(function(resolve, reject) {
if (i > 3) {
resolve();
return;
}
window.setTimeout(function() {
console.log(i);
$('#output').append(i).append('<br/>');
i += 1;
pro().then(function() {
resolve()
}).catch(function() {
reject()
});
}, 2000);
});
}
pro().then(function () { $('#output').append("now here"); })
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="output"></div>

Categories