How to determine completion? - mysql

I am creating currency rates website backend in node js with MongoDB and MySQL,
At first I am storing data into MongoDB from API and afterwards, for saving RAM and CPU I have decided to create and store analytical data into MySQL.
Please look at following code,
update24HRateArr: () => {
var da = [];
db.query('TRUNCATE TABLE `rate24h`', (xerr, xres) => {
if (xerr) console.log(xerr.message);
});
mdb.currency((currList) => {
if (currList && currList.length > 0) {
currList.length = 50;
for (var c = 0; c < currList.length; c++) {
mdb.rateArr(currList[c], '24h', (data) => {
if (data && data.length > 0) {
for (var i = 0; i < data.length; i++) {
var tmp = [];
tmp.push(data[i].id);//1->id
tmp.push(i);//2->number
tmp.push(data[i].time);//3->time value
tmp.push(data[i].price_usd);//4->price usd
tmp.push(data[i].price_btc);//5->price btc
tmp.push(data[i].price_inr);//6->price inr
tmp.push(fn.time.unix());//7->DB update time
da.push(tmp);
}
//main area for done call
/*
if (da.length == 1200) {
db.query('INSERT INTO `rate24h` VALUES ?', [da], (err, datax) => {
if (err) console.log(err);
else {
console.log(`${fn.time.timeStamp()} Data(${datax.affectedRows}) Inserted for Rate24H`);
}
});
console.log(da);
}*/
console.log(`inside i ${da.length}`);
}
console.log(`inside iRateArr ${da.length}`);
});
//console.log(`inside c ${da.length}`); <- always 0 no way
}
}
else {
console.log('Currency Loading failed');
}
});
},
Now, I know that length of da var is gonna be 1200 in this case because 50 currencies and 24 hours but in some cases it's flexible,
I can't exactly determine when this da var updating will be completed via for loops so I can execute insert query to mysql
that if(da.length ===1200) is not enough I need exact point that I can execute INSERT query.
Thank you

Related

Cannot get variable from sql query in Node

Sorry, I read about handling async functions in order to get variable names from them but I am not sure what I am doing wrong and how to handle it.
for(let j = 0; j < ga.length; j++) {
var sql = "SELECT * FROM matches WHERE clh = '"+ga[j]+"'"
const dbq = db.query(sql, function(err, result) {
if (err) console.log(err);
var gs1 = 0;
var gs2 = 0;
var pts1 = 0;
var w1 = 0;
var d1 = 0;
var l1 = 0;
for (let i = 0; i < result.length; i++) {
gs1 += result[i].gsh;
gs2 += result[i].gsa;
const r = mgs1(result[i].gsh, result[i].gsa);
if (r == 3) w1 += 1;
if (r == 1) d1 += 1;
if (r == 0) l1 += 1;
var gd1 = gs1 - gs2;
var r1 = [result[i].clh, result.length, w1, d1, l1, gs1, gs2, gd1 ];
}
gs4.push(r1);
if (gs4.length == 6) {
return gs4;
}
})
}
}
This function returns the array that I want but I am not sure how to access it outside the db.query block. I read posts about handling variables from async functions but I just can't seem to do it in this example. Thanks a lot in advance
I guess you have defined const gs4 = [] somewhere in code you did not show us. That's part of the answer to your question: it will be populated after your callback from db.query() completes.
The rest of the answer: it is not populated until after the callback completes. Also, the return from inside your callback is meaningless; it just returns to db.query() .
Also, db.query() returns to its caller instantly, long before it calls its callback. So your loop tries to run multiple queries concurrently. I guess the result in gs4 will accumulate the results from all the queries.
With respect, I believe a quick jump up the learning curve for Promises or async / await lies in your near future.
This may help : node.js mysql query in a for loop
If you would like to query the database the correct way, you should use the embedded functions that comes with database driver. For string interpolation and returning data for your functions.
exports.lookupLogin = (req, res, next) => {
let sql = 'SELECT e.employee_id, e.login, e.password FROM employee e WHERE e.login=?';
postgres.client.query(sql, [req.body.login], (error, result, fields) => {
if (err) {
return res.status(500).json({ errors: ['Could not do login'] });
}
res.status(200).json(result.rows);
});
};
For more information you can check the mysql documentation to use with nodejs.

API call in lazy-load function, limiting the api response

I've set up a project where Im limiting the API response to 5, and upon scrolling to the bottom o the page, I make a new API call to fetch the next 2 items in the API. But with the current code it only checks if the 5 items previously fetched exists in the cards state. Im quite unsure as to how to go about fetching the 2 next items in the API? Does anyone have any suggestions as to how to go about this? Thanks,
var app = new Vue({
el: '#app',
data: {
cards: []
},
methods: {
scroll(card) {
window.onscroll = () => {
let bottomOfWindow = document.documentElement.scrollTop +
window.innerHeight === document.documentElement.offsetHeight;
if(bottomOfWindow) {
const url =
'https://api.jsonbin.io/b/5cab36508b8d1301a25bd8fa/1/';
axios.get(url)
.then(response => {
for (var i = 0; i < this.cards.length; i++) {
console.log('Cards id: ', this.cards[i].id)
if(this.cards[i].id !==
response.data.results[i].id){
for (var x = 0; x < 2; x++) {
this.cards.push(response.data.results[x])
}
} else{
console.log('No more cards to load')
}
}
}
})
}
}
},
getAPI(){
const url = 'https://api.jsonbin.io/b/5cab36508b8d1301a25bd8fa/1/';
axios.get(url)
.then(response => {
for (var i = 0; i < 5; i++) {
this.cards.push(response.data.results[i]);
}
})
.catch(function (error) {
console.log(error);
})
.then(function () {
// always executed
});
console.log(this.cards)
}
},
mounted() {
this.scroll(this.card)
}
})
Changed the method in which you do the checking. Instead of doing it from cards length you loop through the results length and once you reach a card that doesnt exist you add them, keep track of the amount added and return after 2 or when there is none left. I changed the loop logic to so.
//Card with position i from results doesn't exist
if(this.cards[i] == undefined){
//add this card - maybe add more logic to check for duplicate incase of reordering of response
this.cards.push(response.data.results[i])
//track card added
cardsAdded++;
} else {
console.log('No more cards to load')
}
//check if cards added has reach limit of 2
if(cardsAdded == 2)
return;
See: https://jsfiddle.net/as4dm03q/

How to use result array of a query in another query in Mysql+Node JS?

I want to use the result of first query(sql1) in second query(sql2). The result of first query(sql1) is getting in .ejs page but no result for the second query(sql2).
var sql1 = 'SELECT * FROM `Rooms`';
con.query(sql1,function(err,rows,fields){
if(!err)
{
var count=rows.length;
for(i=0;i<count;i++)
{
arr_room[i]=rows[i].room_name;
}
}
else
{
console.log('error...');
}
});
var sql2 = 'SELECT * FROM Lights WHERE room_name =? ' ;
con.query(sql,arr_room[0],function(err,rows,fields){
if(!err)
{
var count=rows.length;
for(i=0;i<count;i++)
{
arr_icon[i]=rows[i].icon;
}
}
else
{
console.log('error...');
}
res.render('lighting',{arr_icon,arr_room});
});
You need to nest sql2 into sql1, in nodejs everything is asynchronous, that means you must wait for something to finish first.
And you had a typo on the second query, you called sql instead of sql2
var sql1 = 'SELECT * FROM `Rooms`';
con.query(sql1, function(err, rows, fields) {
if (!err) {
var count = rows.length;
//for (i = 0; i < count; i++) {
// arr_room[i] = rows[i].room_name;
//}
if (count) {
// simplified version instead of for
var arr_room = rows.map(i => i.room_name);
// you can safely use it inline since data comes straight from the database
// query will use `in` condition: room_name in ('roomX','roomY', 'roomZ')
var sql2 = `SELECT * FROM Lights WHERE room_name in ('${arr_room.join("','")}') `;
con.query(sql2, function(err, rows, fields) {
if (!err) {
var count = rows.length;
for (i = 0; i < count; i++) {
arr_icon[i] = rows[i].icon;
}
} else {
console.log('error...');
}
res.render('lighting', {
arr_icon,
arr_room
});
});
} else {
console.log('no records to pass for sql2');
}
} else {
console.log('error...');
}
});
I know this question has an answer already, but I wanted to contribute a SQL-only solution: using a subquery instead of executing two separate queries and operating on their results in Node.js.
SELECT
*
FROM lights
WHERE
room_name IN (
SELECT room_name FROM rooms
);

variable value becomes undefined in NodeJS ExpressJS

I am working with NodeJS using ExpressJS framework in a mysql backend. I am running a query inside a for loop and my loop and work afterwards depends on the return value of the query. I am not very good with mysql query so I am running it through a for loop.
The problem is, due asynchronous [I guess!], the for loop ends long before the query result comes out.
Here is my code:
function search_people_step2(user_id, search_criteria, user_friend)
{
var first_name_friends = [];
var last_name_friends = [];
for(var i = 0; i < user_friend.length; i++)
{
con.query("SELECT first_name, second_name FROM user WHERE userid = ?", user_friend[i],function(err, rows)
{
if(err)
{
//error;
}
else
{
if(rows.length == 0)
{
//nothing gets returned
}
else {
console.log(rows);
first_name_friends[i] = rows[0].first_name;
last_name_friends[i] = rows[0].second_name;
}
}
});
}
Now,I can get the value (using console.log) inside the query statement, however, on the outside, the value becomes empty (undefined) since the rest of the code has already been computed.
How can I solve this?
Thanks in advance.
The first thing that I find weird in your code is that you are not using an IN statement in your SQL query (not directly related to your problem though) which means you are making as many requests as there are entries in user_friend. The problem is that the SQL library is implemented asynchronously and you cannot avoid it. BUT you can handle it elegantly with Promises which are ES6 features:
(I didn't test the code but I think it should work)
function search_people_step2(user_id, search_criteria, user_friend)
{
return new Promise((resolve,reject)=>{
var first_name_friends = [];
var last_name_friends = [];
var placeHolders=user_friend.map(()=>"?").join(",");
con.query("SELECT first_name, second_name FROM user WHERE userid IN ("+placeHolders+")",user_friend,(err,rows)=>{
if(err)
reject(err);
else{
rows.forEach(row=>{
first_name_friends.push(row.first_name);
last_name_friends.push(row.second_name);
});
resolve({first_name_friends,last_name_friends});
}
});
});
}
And call your function like this :
search_people_step2(id,crit,friends).then(result=>{
//handle result asynchronously as there is no choice
console.log(result.first_name_friends);
console.log(result.last_name_friends);
}).catch(err=>{
//handle error
});
You are right, your problem is the asynchronous nature of the mysql call. You have to provide a callback to your search_people_step2 function.
You may change it like this:
search_people_step2(user_id, search_criteria, user_friend, callback)
In your function body you may use a library called async to handle all the callbacks properly. Here is an example for the usage:
async.eachSeries(user_friend, function(item, eachCb){
con.query("SELECT first_name, second_name FROM user WHERE userid = ?",
user_friend[i],function(err, rows) {
if(err) {
eachCb('error');
}
else {
if(rows.length == 0){
//nothing gets returned
eachCb(null);
}
else {
console.log(rows);
first_name_friends.push(rows[0].first_name);
last_name_friends.push(rows[0].second_name);
eachCb(null);
}
}
}, callback);
});
This calls each query in order on every item of the array and calls the inner callback if finished. When all items are processed or an error occured the outer callback is called. See the async library for further documentation.
simplest solution is
function search_people_step2(user_id, search_criteria, user_friend)
{
var first_name_friends = [];
var last_name_friends = [];
for(var i = 0; i < user_friend.length; i++)
{
con.query("SELECT first_name, second_name FROM user WHERE userid = ?", user_friend[i],function(err, rows)
{
if(err)
{
//error;
}
else
{
if(rows.length == 0)
{
//nothing gets returned
}
else {
console.log(rows);
first_name_friends[i] = rows[0].first_name;
last_name_friends[i] = rows[0].second_name;
}
if(i==user_friend.length-1){
//do your work here which you want to perform in end
}
}
});
}
or use async library
var async = require('async');
var first_name_friends = [];
var last_name_friends = [];
async.series([function(cb){
function search_people_step2(user_id, search_criteria, user_friend)
{
for(var i = 0; i < user_friend.length; i++)
{
con.query("SELECT first_name, second_name FROM user WHERE userid = ?", user_friend[i],function(err, rows)
{
if(err)
{
//error;
}
else
{
if(rows.length == 0)
{
//nothing gets returned
}
else {
console.log(rows);
first_name_friends[i] = rows[0].first_name;
last_name_friends[i] = rows[0].second_name;
}
if(i==user_friend.length-1){
cb()
}
}
});
}
},function(cb){
//do your work here
}],function(err){})

How can I do this asyn feature in nodejs

I have a code to do some calculation.
How can I write this code in an asyn way?
When query the database, seems we can not get the results synchronously.
So how to implement this kind of feature?
function main () {
var v = 0, k;
for (k in obj)
v += calc(obj[k].formula)
return v;
}
function calc (formula) {
var result = 0;
if (formula.type === 'SQL') {
var someSql = "select value from x = y"; // this SQL related to the formula;
client.query(someSql, function (err, rows) {
console.log(rows[0].value);
// *How can I get the value here?*
});
result = ? // *How can I return this value to the main function?*
}
else
result = formulaCalc(formula); // some other asyn code
return result;
}
Its not possible to return the result of an asynchronous function, it will just return in its own function scope.
Also this is not possible, the result will always be unchanged (null)
client.query(someSql, function (err, rows) {
result = rows[0].value;
});
return result;
Put a callback in the calc() function as second parameter and call that function in the client.query callback with the result
function main() {
calc(formula,function(rows) {
console.log(rows) // this is the result
});
}
function calc(formula,callback) {
client.query(query,function(err,rows) {
callback(rows);
});
}
Now if you want the main to return that result, you also have to put a callback parameter in the main and call that function like before.
I advice you to check out async its a great library to not have to deal with this kind of hassle
Here is a very crude way of implementing a loop to perform a calculation (emulating an asynchronous database call) by using events.
As Brmm alluded, once you go async you have to go async all the way. The code below is just a sample for you to get an idea of what the process in theory should look like. There are several libraries that make handling the sync process for asynch calls much cleaner that you would want to look into as well:
var events = require('events');
var eventEmitter = new events.EventEmitter();
var total = 0;
var count = 0;
var keys = [];
// Loop through the items
calculatePrice = function(keys) {
for (var i = 0; i < keys.length; i++) {
key = keys[i];
eventEmitter.emit('getPriceFromDb', {key: key, count: keys.length});
};
}
// Get the price for a single item (from a DB or whatever)
getPriceFromDb = function(data) {
console.log('fetching price for item: ' + data.key);
// mimic an async db call
setTimeout( function() {
price = data.key * 10;
eventEmitter.emit('aggregatePrice', {key: data.key, price: price, count: data.count});
}, 500);
}
// Agregate the price and figures out if we are done
aggregatePrice = function(data) {
count++;
total += data.price;
console.log('price $' + price + ' total so far $' + total);
var areWeDone = (count == data.count);
if (areWeDone) {
eventEmitter.emit('done', {key: data.key, total: total});
}
}
// We are done.
displayTotal = function(data) {
console.log('total $ ' + data.total);
}
// Wire up the events
eventEmitter.on('getPriceFromDb', getPriceFromDb);
eventEmitter.on('aggregatePrice', aggregatePrice);
eventEmitter.on('done', displayTotal);
// Kick of the calculate process over an array of keys
keys = [1, 2, 3]
calculatePrice(keys);