How to repeatedly execute nodejs mysql query until desire result come out? - javascript

conn.connect(function (err) {
if (err) throw err;
var prizeCode = generatePrizeCode();// this method return a 5-digit code
var query = "SELECT * FROM user WHERE code = ? ";
var values = [[prizeCode]];
conn.query(query, [values], function (err, result) {
if (err) throw err;
// Here I want to re-execute the above query if the result is not empty
});
});
In the above code, I want to execute query as long as the result contain data. But I cannot use the loop like following pseucode,
// if the result is empty, the generated code does not exist in database. So it can be used.
while(result.length != 0){
var result = conn.query("SELECT * FROM user WHERE code = abc");
}
How can I achieve this?

You'll have to use callbacks or promises/async functions. Here's how it could be written with callbacks:
const mysql = require('mysql');
const retryLimit = 50;
const connection = mysql.createConnection({
database: 'test',
host: 'localhost',
password: 'hunter2',
user: 'dave',
});
function getData(attempts, cb) {
if (attempts < retryLimit) { // we haven't exausted our attempts yet
const code = generatePrizeCode();
connection.query('SELECT * FROM user WHERE code = ?', code, (err, result) => {
if (err) {
return cb(err);
}
if (result.length > 0) { // code already exists
getData(attempts + 1, cb); // recurse
} else { // this is a new code
cb(null, code); // return the new code via the callback function
}
});
} else { // we have exausted our attempts
return cb(new Error('retry limit exceeded'));
}
}
getData(0, (err, code) => {
// do what you want here, e.g., console.log(code)
connection.end();
});
Note that this can cause node to crash if you recurse too many times and exceed the maximum call stack. One way around that is to call setImmediate or setTimeout instead of recursing directly. Instead of the line
getData(attempts + 1, cb); // recurse
use
setImmediate(() => {
getData(attempts + 1, cb); // recurse
});
or
// recurse, using setImmediate every 1000th time
if (attempts % 1000 === 0) {
setImmediate(() => {
getData(attempts + 1, cb); // recurse
});
} else {
getData(attempts + 1, cb); // recurse
}
Using promises and async/await style would clean this up a lot and probably look more like what you're used to (note this uses the promise-mysql library):
const mysql = require('promise-mysql');
async function getData(connection) {
const retryLimit = 50;
for (let i = 0; i < retryLimit; i++) {
const code = generatePrizeCode();
const result = await connection.query('SELECT * FROM user WHERE code = ?', code);
if (result.length === 0) { // this code doesn't exist yet
return code;
}
}
throw new Error('retry limit exceeded');
}
(async () => {
try {
const connection = await mysql.createConnection({
database: 'test',
host: 'localhost',
password: 'hunter2',
user: 'dave',
});
try {
const code = await getData(connection);
// do what you want here, e.g., console.log(code)
} finally {
connection.end();
}
} catch (err) {
console.log(err);
}
})();

basically you gonna need to work with async\await or promises(pretty much the same).
https://javascript.info/async-await
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
this way your gonna be able to only return when you get the right result for you.

var mysql = require('mysql');
var pool = mysql.createPool({
host : 'YOUR_HOST_NAME',
user : 'YOUR_USER_NAME',
password : 'YOUR_PASSWORD',
database : 'YOUR_DATABASE'
});
pool.getConnection(function(err, connection) {
// connected! (unless `err` is set)
});
connection = mysql.createPool
var retryLimit=0;
var getData = function () {
if(retryLimit <= 50)
{
retryLimit++;
connection.query('SELECT * FROM user WHERE code = abc', function (error, results, fields) {
if (error) {throw error;}
else if(result.length <1) {
getData();
//call the same method again.
}
});
}
}
getData();
You could add else statements and do whatever you want.

Related

JS async function returning undefined although calling it inside an asynchronous function

I am using nodeJs Express and I have an async function which is used in another function.
here is my code:
/* get user info */
const getUserInfo = async (req) => {
let userID = req.cookies.userId;
if(!userID) return null;
await connection.query('SELECT * FROM users WHERE id = ' + userID,
function (err, rows, fields) {
if (err) throw err
// if user not found
if (rows.length === 0) {
return null;
}
// if user found
else {
return rows[0];
}
});
}
/* display dashboard page */
router.get("/", async function (req, res, next) {
let userInfo = await getUserInfo(req);
console.log(userInfo) // It's result is undefined
if (userInfo) {
res.render('dashboard/profile', {
fullName: userInfo.fname + " " + userInfo.lname,
email: userInfo.email,
phone: userInfo.phone,
});
}
else {
res.render('authentication/register', {
title: 'ثبت نام',
});
}
});
how to resolve this problem? I need userInfo retun me some data.
await is only useful if the value on the right-hand side is a promise.
connection.query is taking a callback function, which implies it isn't returning a promise.
You need to either:
Find out how to make the API you are using return a promise (if that is possible)
Wrap the callback in a promise
Replace the API with one that supports promises natively
You also need getUserInfo to have a return statement of its own.
You have to return some value from your getUserInfo function
If connection query doesn't support promise you should wrap it like this
/* get user info */
const getUserInfo = async(req) => {
let userID = req.cookies.userId;
if (!userID) return null;
return new Promise((resolve, reject) => {
connection.query('SELECT * FROM users WHERE id = ' + userID,
function(err, rows, fields) {
if (err) {
reject(err)
return;
}
// if user not found
if (rows.length === 0) {
resolve(null)
}
// if user found
else {
resolve(rows[0]);
}
});
});
}

Node.js promise fails intermittently, even when handled

I'm learning to use MongoDB by creating a simple blog app. However, a portion of my code that saves a given post seems to give problems with promises occasionally, but not always, and whether the code succeeds simply seems to be luck.
Each post in my database is stored with the following schema:
{
title: String,
author: String,
body: String,
slug: String,
baseSlug: String,
published: { type: Boolean, default: false }
}
The slug defines the link used to access the blog post, and is automatically generated based upon the title of the blog post. However, if article titles are duplicates, the slug will have a number added to the end to differentiate it from similar articles, while the baseSlug will remain the same. For example:
I create the post "My first post", and it is assigned the baseSlug of "my-first-post". Because no other posts have the same baseSlug, the slug is also set to be "my-first-post".
I create another post called "My first post", and it is assigned the baseSlug of "my-first-post". However, because another post has the same baseSlug, it is assigned the slug "my-first-post-1".
To create this behavior, I wrote the following addpost route in Express:
app.post("/addpost", (req, res) => {
let postInfo = req.body;
for (key of Object.keys(postInfo)) {
if (postInfo[key] == "true") postInfo[key] = true;
}
let slug = postInfo.title
.toLowerCase()
.split(" ")
.filter(hasNumber) // return /\d/.test(str);
.slice(0, 5)
.join("-");
postInfo.slug = slug;
var postData;
Post.find({ baseSlug: postInfo.slug }, (error, documents) => {
if (documents.length > 0) {
let largestSlugSuffix = 0;
for (let document of documents) {
var fullSlug = document.slug.split("-");
var suffix = fullSlug[fullSlug.length - 1];
if (!isNaN(suffix)) {
if (parseInt(suffix) > largestSlugSuffix) {
largestSlugSuffix = suffix;
}
}
}
largestSlugSuffix++;
postInfo.baseSlug = postInfo.slug;
postInfo.slug += "-" + largestSlugSuffix;
} else {
postInfo.baseSlug = postInfo.slug;
}
postData = new Post(postInfo);
})
.then(() => {
postData
.save()
.then(result => {
res.redirect("/");
})
.catch(err => {
console.log(err);
res.status(400).send("Unable to save data");
});
})
.catch(err => {
console.log(err);
res.status(400).send("Unable to save data");
});
});
This code seems to work most of the time, but sometimes it fails, and outputs the following:
TypeError: Cannot read property 'save' of undefined
at C:\Users\User\BlogTest\app.js:94:18
at processTicksAndRejections (internal/process/task_queues.js:94:5)
(For reference, line 94 in my file is postData.save())
I suspect it is because the main body of the function takes longer than it should to execute, and the postData variable is not yet defined. However, postData.save() should not be executed until the promise finishes, because of the .then() callback function.
Why is my code behaving like this? Is there any way to fix it?
The issue is that you are mixing promises with callbacks and closures. That's not how this is intended to work.
When you chain promises, whatever you return in the first promise handler will be added as an input to the next one. And if you return a promise, that promise will be resolved first before being sent to the next thenable.
So you need to return promises from your promises, like this:
app.post("/addpost", (req, res) => {
let postInfo = req.body;
for (key of Object.keys(postInfo)) {
if (postInfo[key] == "true") postInfo[key] = true;
}
let slug = postInfo.title
.toLowerCase()
.split(" ")
.filter(hasNumber) // return /\d/.test(str);
.slice(0, 5)
.join("-");
postInfo.slug = slug;
// var postData; <-- Don't do that
Post.find({ baseSlug: postInfo.slug })
.then((documents) => {
if (documents.length > 0) {
let largestSlugSuffix = 0;
for (let document of documents) {
var fullSlug = document.slug.split("-");
var suffix = fullSlug[fullSlug.length - 1];
if (!isNaN(suffix)) {
if (parseInt(suffix) > largestSlugSuffix) {
largestSlugSuffix = suffix;
}
}
}
largestSlugSuffix++;
postInfo.baseSlug = postInfo.slug;
postInfo.slug += "-" + largestSlugSuffix;
} else {
postInfo.baseSlug = postInfo.slug;
}
return new Post(postInfo);
// We could actually have called postData.save() in this method,
// but I wanted to return it to exemplify what I'm talking about
})
// It is important to return the promise generated by postData.save().
// This way it will be resolved first, before invoking the next .then method
.then( (postData) => { return postData.save(); })
// This method will wait postData.save() to complete
.then( () => { res.redirect("/"); })
.catch( (err) => {
console.log(err);
res.status(400).send("Unable to save data");
});
});
It can be greatly simplified with async/await:
app.post("/addpost", async (req, res) => {
try {
let postInfo = req.body;
for (key of Object.keys(postInfo)) {
if (postInfo[key] == "true") postInfo[key] = true;
}
let slug = postInfo.title
.toLowerCase()
.split(" ")
.filter(hasNumber)
.slice(0, 5)
.join("-");
postInfo.slug = slug;
let documents = await Post.find({ baseSlug: postInfo.slug });
if (documents.length > 0) {
let largestSlugSuffix = 0;
for (let document of documents) {
var fullSlug = document.slug.split("-");
var suffix = fullSlug[fullSlug.length - 1];
if (!isNaN(suffix)) {
if (parseInt(suffix) > largestSlugSuffix) {
largestSlugSuffix = suffix;
}
}
}
largestSlugSuffix++;
postInfo.baseSlug = postInfo.slug;
postInfo.slug += "-" + largestSlugSuffix;
} else {
postInfo.baseSlug = postInfo.slug;
}
let postData = new Post(postInfo);
await postData.save();
res.redirect("/");
} catch (err) {
console.log(err);
res.status(400).send("Unable to save data");
};
});
You are mixing callbacks and promises and while it may do something, I'm not sure what it will do exactly. You should pick one or the other and not mix them as much as possible. I would recommend picking promises if you are using a language that supports async/await, otherwise callbacks.
So for example your outter handler could be an async function
app.post("/addpost", async (req, res) => {
//...
})
Your real bug is in handling Post.find you are handling it somewhat with a callback and somewhat with a promise, and probably whats happening is that its random which one will get called first the callback or the promise resolution. Instead of both you should just do this now that you have an async function:
try {
const posts = await Post.find({ baseSlug: postInfo.slug });
// stuff you were doing in the callback
const post = new Post(postInfo)
// Now the promise code
await post.save()
// success!
res.redirect("/");
} catch (err) {
// With an async function you can just catch errors like normal
console.log(err);
res.status(400).send("Unable to save data");
}
If you're not using webpack or typescript and cannot target es7 then and thus cannot use async/await then I would recommend just using callbacks, do not use .then or .catch and that would look more like:
function error(err) {
console.log(err)
res.status(400).send("Unable to save data")
}
Post.find({ baseSlug: postInfo.slug }, (err, documents) => {
if (err) return error(err)
// stuff you're doing in the callback now
const post = new Post(postInfo)
post.save((err) => {
if (err) return error(err)
// success!
res.redirect("/");
})
})

Node.js not executing last expression in callback

I’ve written this code to query a MySQL database in Node 8:
const getDB = require('./db');
function getCrawls(cb) {
const db = getDB();
const rows = db.query('select * from crawls', (err, result) => {
console.log('got result', result);
cb(result);
});
}
getCrawls(c => console.log('done', c));
However, I only get the following output when I run it:
got result []
Now the strange thing is it works if I add another console.log after the callback is called:
const getDB = require('./db');
function getCrawls(cb) {
const db = getDB();
const rows = db.query('select * from crawls', (err, result) => {
console.log('got result', result);
cb(result);
console.log('complete');
});
}
getCrawls(c => console.log('done', c));
Now I get this output:
got result []
done []
It seems that the last statement of the query callback isn’t being called, does anybody have any idea why this could be happening?
Edit:
Here's the code for getDB
const mysql = require('mysql');
function getDB() {
const db = mysql.createConnection({
host: process.env.MYSQL_HOST,
user: process.env.MYSQL_USER,
password: process.env.MYSQL_PASSWORD,
database: process.env.MYSQL_DATABASE,
})
db.connect();
return db;
}
module.exports = getDB;
It sounds like the error may be related to the MySQL module?
Using the info we have from your code, it should work fine; looking at the following snippet.
It seems that your code is stuck executing cb(result); maybe there is an un-catched exception there?
function query(data, callback) {
setTimeout(() => {
callback(false, ['result']);
}, 1000);
}
function getCrawls(cb) {
const rows = query('select * from crawls', (err, result) => {
console.log('got result', result);
cb(result);
console.log('complete');
});
}
getCrawls(c => console.log('done', c));

Jest TypeError: function not found

I am trying to run a test with jest, except it cannot find my function. I am exporting multiple functions from one file using module.exports = {}.
Here is my test file:
const queries = ('../config/queries');
test('Check Activation Code. -- checkActivationCode(test#gmail.com, 0123456789) ', () => {
let email = 'test%40gmail.com';
let code = 1234567890;
let result = "";
queries.checkActivationCode(email, code, function(error, result) {
if (error) result = false;
else result = true;
});
expect(result).toBe(true);
});
My file structure is as follows, /config/queries/index.js, I am able to access the functions in my other files just fine.
Here is my queries/index.js file:
module.exports = {
checkActivationCode: function(email, code, callback) {
pool.getConnection(function(error, connection) {
connection.query('SELECT code FROM confirmation WHERE email = ?', [email.toLowerCase()], function(error, results) {
if (error) callback(error);
try {
if (results[0].code === code) {
callback(null, true);
} else {
callback(null, false);
}
} catch (e) {
callback(null, false);
}
});
connection.release();
});
}
}
I forgot to require my queries.
const queries = ('../config/queries');
to
const queries = require('../config/queries');
Simple typo. Thanks #BenceGedai for catching that.

Mongoose fetching data, setting in a list (undefined)

I am trying to fetch all messages of two users from MongoDB using a custom function. I am not able to set list. I have no idea how to use callback here.
fetchall = function(chatuser, me) {
var allmessage = [] ;
var promise = this.model.find({},function(err, docs) {
if (err) { return console.error(err);
}
console.log(docs); //working
// doSomethingElse(docs);
allmessage = JSON.stringify(docs);
return allmessage;
}).exec();
// promise.then(doSomethingElse(cc));
console.log('all',allmessage); // undefined
return allmessage;
};
here is Example
fetchall = function(chatuser, me, cb) {
var allmessage = [];
var promise = this.model.find({}, function(err, docs) {
if (err) {
// here cb is callback
return cb(err)
} else {
console.log(docs); //working
if (Array.isArray(docs) && docs.length > 0) {
// do it here
cb(null, docs)
} else {
// throw error here
// no result found like
cb()
}
}).exec();
};

Categories

Resources