select max id in mysql nodejs - javascript

I want to get max id from mysql, but I keep getting error.
abc.jsx
async function mintNFT() {
let id = await getNumberOfRow()
console.log("this is id", id)
return id;
}
async function getNumberOfRow() {
axios.get("http://localhost:4000/getNumberOfRow").then(response => {
console.log("response ", response.data[0])
return response.data[0];
})
.then(posts => {
return posts[0]
})
.then((err) => {
console.log(err);
})
return;
}
index.js
app.get("/getNumberOfRow", (req, res) => {
db.query("SELECT MAX(id) FROM NFTDetails", (err, result) => {
if (err) {
console.log(err)
}
res.send(result)
});
})
Output
this is id undefined
Minter.jsx:47 response {MAX(id): 154}
Minter.jsx:54 undefined
I have added async-await, why it still displays "this is id" first ? How can I fix it so I can get the max id?
Edit
After I edited my code to this, I get different output.
async function getNumberOfRow() {
try {
const response = await axios.get("http://localhost:4000/getNumberOfRow");
console.log("response ",response.data[0])
return response.data[0][0]; // you could extract the first part to a variable `posts`, but doing so just adds a variable
} catch (err) {
console.log(err);
}
}
Output
response {MAX(id): 154}MAX(id): 154[[Prototype]]: Object
Minter.jsx:32 this is id undefined

You need to return the call to axios.get in getNumberOfRow, and it doesn't need to be async based on how you're handling it.
function getNumberOfRow() {
return axios.get("http://localhost:4000/getNumberOfRow").then(response => {
console.log("response ",response.data[0])
return response.data[0]["MAX(id)"];
})
.catch((err) => {
console.log(err);
})
}
As an async function, you would write it like this.
async function getNumberOfRow() {
try {
const response = await axios.get("http://localhost:4000/getNumberOfRow");
console.log("response ",response.data[0])
return response.data[0]["MAX(id)"]; // you could extract the first part to a variable `posts`, but doing so just adds a variable
} catch (err) {
console.log(err);
}
}

Related

Method returns undefined the first time it is called

I have a method that selects distinct values from a database as shown below:
function displayCategories(res, req) {
query = `SELECT DISTINCT name FROM product_category;`;
connection.query(query, function (err, rows) {
if (err) {
console.log(err);
res.render("home");
throw err;
} else {
session = req.session;
session.categories = rows[0];
}
});
}
I then have a button with the method POST and action /categories
The displayCategories is called when the button is clicked as follows:
router.post('/categories', function (req, res) {
displayCategories(res, req);
if (session.categories === undefined) {
console.log("categories is undefined");
} else {
console.log("categories is defined");
console.log(session.categories);
}
})
I added some console logs for test purposes. The issue I am having is that the first time I click the button, it returns undefined. Each time I click it again, it prints the correct data for session.categories as shown below:
Is there a simple fix for this issue?
The code is calling a displayCategories as if it were synchronous, but it is running asynchronous code with the callback.
There are multiple possible solutions for that but one of them would be to use Promises, like the following:
const displayCategories = (res, req) => new Promise((resolve, reject) => {
// you are not declaring query in this scope, that makes it global
query = `SELECT DISTINCT name FROM product_category;`
connection.query(query, function (err, rows) {
if (err) {
console.error(err)
res.render("home")
reject(err)
} else {
session = req.session
session.categories = rows[0]
resolve()
}
})
})
And the other part with an async function
router.post('/categories', async function (req, res) {
await displayCategories(res, req);
if (session.categories === undefined) { // session is not declared
console.log("categories is undefined");
} else {
console.log("categories is defined");
console.log(session.categories); // session is not declared
}
})
But that's just to make your issue go away, if you want to improve the code even further you can just keep the responsibility of dealing with request and response with the controller action and just use the other function to get the data you want, isolation its responsibility:
const getCategories = () => new Promise((resolve, reject) => {
const query = `SELECT DISTINCT name FROM product_category;`
connection.query(query, (err, rows) => {
if (err) return reject(err)
resolve(rows)
})
})
router.post('/categories', async function (req, res) {
try {
req.session.categories = await getCategories();
if (req.session.categories === undefined) {
console.log("categories is undefined");
} else {
console.log("categories is defined", req.session.categories);
console.log();
}
} catch(e) {
console.error(e)
res.render("home")
}
})

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

Returning undefined result after awaiting function

I am trying to get the result back from function where the result is in the callback. However the result always come back as undefined even though I set it to be the res. Can someone explain why this does not work?
function getData(id, callback) {
return dataModel.findOne({ id }).exec((err, res) => {
if (err) return callback(err)
return callback(null, res)
})
}
async function middleware(req.body) {
try {
let result
await getData(req.body, (err, res) => {
if (err) throw err
result = res
})
await nextFunc(result)... // result is undefined
} catch (err) {
console.log(err)
}
}
You are using callbacks, but in order to make things work with async await you are supposed to use promises
Try
function getData(id, callback) {
return new Promise((resolve, reject) => {
dataModel.findOne({ id }).exec((err, res) => {
if (err) reject(err);
resolve(res);
});
});
}
async function middleware(req.body) {
try {
let result = await getData(req.body);
await nextFunc(result);
} catch (err) {
console.log(err);
}
}

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.

Fetching all stripe customers with async await

I am trying to compile a list of all customers using the Stripe Node API. I need to make continual fetches 100 customers at a time. I believe that I need to use a Promise within the API call to use async await, but I can't for the life of me figure out where to put it. Hoping to make this gist public use and I want to get it right, thanks.
getAllCustomers()
function getMoreCustomers(customers, offset, moreCustomers, limit) {
if (moreCustomers) {
stripe.customers.list({limit, offset},
(err, res) => {
offset += res.data.length
moreCustomers = res.has_more
customers.push(res.data)
return getMoreCustomers(customers, offset, moreCustomers, limit)
}
)
}
return customers
}
async function getAllCustomers() {
const customers = await getMoreCustomers([], 0, true, 100)
const content = JSON.stringify(customers)
fs.writeFile("/data/stripe-customers.json", content, 'utf8', function (err) {
if (err) {
return console.log(err);
}
console.log("The file was saved!");
});
}
IF res in stripe.customers.list({limit, offset}).then(res => ...) is the same as res in the "callback" version of stripe.customers.list({limit, offset}, (err, res) - then you probably could rewrite your code like
const getMoreCustomers = limit => {
const getThem = offset => stripe.customers.list({limit, offset})
.then(res => res.has_more ?
getThem(offset + res.data.length).then(result => res.data.concat(...result)) :
res.data
);
return getThem(0);
};
async function getAllCustomers() {
const customers = await getMoreCustomers(100);
const content = JSON.stringify(customers);
fs.writeFile("/data/stripe-customers.json", content, 'utf8', function (err) {
if (err) {
return console.log(err);
}
console.log("The file was saved!");
});
}
additional to Jaromanda X's answer, it seems there is no offset option to customers api, but starting_after https://stripe.com/docs/api/node#list_customers
So, getMoreCustomers may be fixed like
const getMoreCustomers = starting_after => {
const getThem = starting_after => stripe.customers.list({limit: 100, starting_after: starting_after})
.then(res => res.has_more ?
getThem(res.data[res.data.length - 1]).then(result => res.data.concat(...result)) :
res.data
);
return getThem(starting_after);
};
async function getAllCustomers() {
const customers = await getMoreCustomers(null);
const content = JSON.stringify(customers);
fs.writeFile("/data/stripe-customers.json", content, 'utf8', function (err) {
if (err) {
return console.log(err);
}
console.log("The file was saved!");
});
}

Categories