Modify results from Nested Queries in NodeJS - javascript

Naive to NodeJS and trying to figure out a way to add results from second table to result set of first table in node js.
How can I access results from first query inside the second query?
Following is my code snippet with comments
function getTasks(callback) {
//first query gives result set
connection.query('SELECT * FROM ' + properties.get('database.Table') +' order by timestamp desc', function(err, rows){
if(!err){
//for each result from result set, match on Id and get values from table_2
for (var i = rows.length - 1; i >= 0; i--) {
connection.query('SELECT * FROM table_2 where taskId = "' + rows[i].taskId + '"', function(err, sets){
if(!err){
//if we have any results from table_2 then create an object
if(sets.length > 0){
var setStatus = [];
for (var i = sets.length - 1; i >= 0; i--) {
setStatus[i] = {Status : sets[i].type+'-'+sets[i].status};
}
//add the setStaus object to results from first table (to rows)
//ISSUE: accessing rows[i] here is alwyas undefined??
}
}
});
}
//need to send the rows with updates from nested block
callback(rows);
}
});
UPDATE: async/await solution worked and by changing i to j for inner iterator!

You can handle using async/await
const execute = (query) => {
return new Promise((resove, reject) => {
connection.query(query,
function (err, rows) {
if (err) reject(err);
resove(rows);
});
});
}
const getTasks = async () => {
const query = 'SELECT * FROM ' + properties.get('database.Table') + ' order by timestamp desc';
const rows = await execute(query);
for (var i = rows.length - 1; i >= 0; i--) {
const innerQuery = 'SELECT * FROM table_2 where taskId = "' + rows[i].taskId + '"';
const sets = await execute(innerQuery);
//Do some stuff
if (sets.length > 0) {
var setStatus = [];
for (var i = sets.length - 1; i >= 0; i--) {
setStatus[i] = {
Status: sets[i].type + '-' + sets[i].status
};
}
}
}
return rows;
};
Yau can call either inside await or given below
getTasks().then((rows) => {
console.log(rows);
}).catch((err) => {
console.log(err);
})

The declaration of i in the second for loop overwrites the value of i from the first loop.
You can fix this by changing the variable declared as part of the second loop to something other than i.

Try to use let or const instead of var. Use a different variable name than i for all your iterators. This is probably messing up with your first i, thus leading to rows[i] as undefined.
You also probably want to look for a MySQL node module that supports ES6 Promises like this one : https://www.npmjs.com/package/mysql2

Related

Compare an array with itself for duplicate and store in new array

I have a question, how do I compare values ​​in an array with themselves without the value to be compared being shown as true?
As an example, if the value EUW1_6011808396 occurs again, it should be stored in the array matchingMatches.
The Values of the Array are:
[EUW1_6011808396, EUW1_6011824351, EUW1_6011720277, EUW1_6010413995, EUW1_6010218048, EUW1_6010184913, EUW1_6010131700, EUW1_6009739853, EUW1_6008825456, EUW1_6008833322, EUW1_6008409245, EUW1_6008369887, EUW1_6008355242, EUW1_6007567238, EUW1_6007269146, EUW1_6007226284, EUW1_6007192332, EUW1_6005571988, EUW1_6005438941, EUW1_6005495312, EUW1_6013263286, EUW1_6013193252, EUW1_6012475324, EUW1_6012411610, EUW1_6012315128, EUW1_6012011561, EUW1_6011110477, EUW1_6011026046, EUW1_6009739853, EUW1_6006439870, EUW1_6006434580, EUW1_6005238786, EUW1_6005191249, EUW1_6005026992, EUW1_6005015187, EUW1_6004958241, EUW1_6003811368, EUW1_6002847479, EUW1_6002164371, EUW1_6002148723, EUW1_6015524685, EUW1_6015387328, EUW1_6015402003, EUW1_6014779337, EUW1_6014724668, EUW1_6014701498, EUW1_6014655368, EUW1_6014580839, EUW1_6014429620, EUW1_6014475971, EUW1_6014473252, EUW1_6013334881, EUW1_6013322375, EUW1_6012669749, EUW1_6012635347, EUW1_6012583396, EUW1_6010971941, EUW1_6006896961, EUW1_6006881165, EUW1_6006518887, EUW1_6015745842, EUW1_6015589872, EUW1_6014068520, EUW1_6014044304, EUW1_6007955310, EUW1_6003705297, EUW1_6003569783, EUW1_6002003834, EUW1_6000787500, EUW1_5994465297, EUW1_5993391050, EUW1_5992233473, EUW1_5992169601, EUW1_5984062877, EUW1_5984034743, EUW1_5983855739, EUW1_5983880569, EUW1_5983766086, EUW1_5982931745, EUW1_5982372929, EUW1_6005238786, EUW1_6005191249, EUW1_6005026992, EUW1_6005015187, EUW1_6004958241, EUW1_6002164371, EUW1_6002148723, EUW1_6002057259, EUW1_6002053660, EUW1_6002009239, EUW1_6002003834, EUW1_6001939719, EUW1_6001867883, EUW1_6001022392, EUW1_6000887143, EUW1_6000892356, EUW1_6000787500, EUW1_6000820954, EUW1_5996485374, EUW1_5994559073, EUW1_6010083174, EUW1_6010017420, EUW1_6006898776, EUW1_6006838293, EUW1_6005225782, EUW1_6005135031, EUW1_6003899867, EUW1_6003883079, EUW1_6003786523, EUW1_6002164371, EUW1_6002148723, EUW1_6002057259, EUW1_6002053660, EUW1_6002009239, EUW1_6001022392, EUW1_6000887143, EUW1_6000892356, EUW1_6000787500, EUW1_5999368247, EUW1_5999295110, EUW1_5989231240, EUW1_5989055249, EUW1_5987149834, EUW1_5978125118, EUW1_5969701977, EUW1_5969187233, EUW1_5956294382, EUW1_5955846040, EUW1_5949708234, EUW1_5934525960, EUW1_5916275391, EUW1_5916168691, EUW1_5916132470, EUW1_5907690529, EUW1_5897979620, EUW1_5897921186, EUW1_5896786548, EUW1_5880625543, EUW1_5880541891, EUW1_5878457213, EUW1_6015589872, EUW1_5969852994, EUW1_5969788713, EUW1_5940681289, EUW1_5940556247, EUW1_5937866203, EUW1_5937892773, EUW1_5937768916, EUW1_5937765393, EUW1_5934600651, EUW1_5934512860, EUW1_5934339533, EUW1_5932238516, EUW1_5932166008, EUW1_5932211862, EUW1_5929934534, EUW1_5930153889, EUW1_5931242804, EUW1_5919621815, EUW1_5918236611]
The function which is used for getting the Id for the API call.
/**
* Getting the Team Members and their IDs
*
* #param {info_id|String}
* #return Team Members IDs
* #customfunction
*/
function getTeamMembersIDs(info_id) {
try {
startup();
var teamMembers = getTeamMembersSheet();
var riotIds = [];
for (var counter = 0; counter != teamMembers.length; counter = counter + 1) {
switch (info_id){
case "puuid":
var data = buildURL("https://euw1.api.riotgames.com/lol/summoner/v4/summoners/by-name/"+teamMembers[counter]+"?api_key="+apiKey);
var puuid = data["puuid"];
riotIds.push(puuid);
break;
case "id":
var data = buildURL("https://euw1.api.riotgames.com/lol/summoner/v4/summoners/by-name/"+teamMembers[counter]+"?api_key="+apiKey);
var id = data["id"];
riotIDs.push(id);
break;
case "accountId":
var data = buildURL("https://euw1.api.riotgames.com/lol/summoner/v4/summoners/by-name/"+teamMembers[counter]+"?api_key="+apiKey);
var accountId = data["accountId"];
riotIds.push(accountId);
break;
}
}
return riotIds
} catch (err) {
Logger.log('Failed with error %s', err.message);
}
}
This Function is Used for Getting the Matches that got played per Team Member.
/**
* Getting the Data from the Api which matches got played
*
* #return the matches played
* #customfunction
*/
function getMatchesPlayed() {
try{
startup();
var puuids = getTeamMembersIDs("puuid");
var games = [];
for (var counter = 0; counter != puuids.length; counter = counter + 1) {
var data = buildURL("https://europe.api.riotgames.com/lol/match/v5/matches/by-puuid/"+puuids[counter]+"/ids?start=0&count=20&api_key="+apiKey)
for(var counter2 = 0; counter2 != data.length; counter2 = counter2 + 1){
games.push(data[counter2])
}
}
return games
}catch (err) {
Logger.log('Failed with error %s', err.message);
}
}
The function which should return the Matching Matches in the Array gets from the getMatchesPlayed function.
/**
* Checking the games for matches
*
* #return the matches which match
* #customfunction
*/
function getMatchingMatches() {
try{
var games = getMatchesPlayed();
var matchingMatches = [];
Logger.log(games)
const gettingGames = games.map(element => element)
for (var counter = 0; counter != games.length; counter = counter + 1){
Logger.log(gettingGames[counter])
}
}catch (err) {
Logger.log('Failed with error %s', err.message);
}
}
As I understand, you need to get duplicate ids.
Use the Set data structure for comparing the array values.
// assume this should return an array [EUW1_6011808396, EUW1_6011824351]
var games = getMatchesPlayed(); //
var matched_games = []
// Initialise set data structure.
var set = = new Set();
//Iterate over the games. Runtime complexity O(n)
games.forEach((element) => {
//the case when set does not contain the id we should add it to `set`
if(!set.has(element)){ // O(1)
set.add(element); // O(1)
continue;
}
// if the set already contains the id, we should add it to the matching games array.
matched_games.push(element);
})
I hope this will help.
welcome to Stackoverflow! You have a lot of ways to store duplicate values In a new array, and this is one.
// get duplicartes and store them in a array
function getDuplicates(array) {
let sorted = array.sort();
for (let i = 0; i < sorted.length - 1; i++) {
if (sorted[i + 1] == sorted[i]) {
duplicates.push(sorted[i]);
}
}
}
Another way to get non-unique values
const euws = ['EUW1_6011808396','EUW1_6011824351','EUW1_6011720277','EUW1_6010413995','EUW1_6010218048','EUW1_6010184913','EUW1_6010131700','EUW1_6009739853','EUW1_6008825456','EUW1_6008833322','EUW1_6008409245','EUW1_6008369887','EUW1_6008355242','EUW1_6007567238','EUW1_6007269146','EUW1_6007226284','EUW1_6007192332','EUW1_6005571988','EUW1_6005438941','EUW1_6005495312','EUW1_6013263286','EUW1_6013193252','EUW1_6012475324','EUW1_6012411610','EUW1_6012315128','EUW1_6012011561','EUW1_6011110477','EUW1_6011026046','EUW1_6009739853','EUW1_6006439870','EUW1_6006434580','EUW1_6005238786','EUW1_6005191249','EUW1_6005026992','EUW1_6005015187','EUW1_6004958241','EUW1_6003811368','EUW1_6002847479','EUW1_6002164371','EUW1_6002148723','EUW1_6015524685','EUW1_6015387328','EUW1_6015402003','EUW1_6014779337','EUW1_6014724668','EUW1_6014701498','EUW1_6014655368','EUW1_6014580839','EUW1_6014429620','EUW1_6014475971','EUW1_6014473252','EUW1_6013334881','EUW1_6013322375','EUW1_6012669749','EUW1_6012635347','EUW1_6012583396','EUW1_6010971941','EUW1_6006896961','EUW1_6006881165','EUW1_6006518887','EUW1_6015745842','EUW1_6015589872','EUW1_6014068520','EUW1_6014044304','EUW1_6007955310','EUW1_6003705297','EUW1_6003569783','EUW1_6002003834','EUW1_6000787500','EUW1_5994465297','EUW1_5993391050','EUW1_5992233473','EUW1_5992169601','EUW1_5984062877','EUW1_5984034743','EUW1_5983855739','EUW1_5983880569','EUW1_5983766086','EUW1_5982931745','EUW1_5982372929','EUW1_6005238786','EUW1_6005191249','EUW1_6005026992','EUW1_6005015187','EUW1_6004958241','EUW1_6002164371','EUW1_6002148723','EUW1_6002057259','EUW1_6002053660','EUW1_6002009239','EUW1_6002003834','EUW1_6001939719','EUW1_6001867883','EUW1_6001022392','EUW1_6000887143','EUW1_6000892356','EUW1_6000787500','EUW1_6000820954','EUW1_5996485374','EUW1_5994559073','EUW1_6010083174','EUW1_6010017420','EUW1_6006898776','EUW1_6006838293','EUW1_6005225782','EUW1_6005135031','EUW1_6003899867','EUW1_6003883079','EUW1_6003786523','EUW1_6002164371','EUW1_6002148723','EUW1_6002057259','EUW1_6002053660','EUW1_6002009239','EUW1_6001022392','EUW1_6000887143','EUW1_6000892356','EUW1_6000787500','EUW1_5999368247','EUW1_5999295110','EUW1_5989231240','EUW1_5989055249','EUW1_5987149834','EUW1_5978125118','EUW1_5969701977','EUW1_5969187233','EUW1_5956294382','EUW1_5955846040','EUW1_5949708234','EUW1_5934525960','EUW1_5916275391','EUW1_5916168691','EUW1_5916132470','EUW1_5907690529','EUW1_5897979620','EUW1_5897921186','EUW1_5896786548','EUW1_5880625543','EUW1_5880541891','EUW1_5878457213','EUW1_6015589872','EUW1_5969852994','EUW1_5969788713','EUW1_5940681289','EUW1_5940556247','EUW1_5937866203','EUW1_5937892773','EUW1_5937768916','EUW1_5937765393','EUW1_5934600651','EUW1_5934512860','EUW1_5934339533','EUW1_5932238516','EUW1_5932166008','EUW1_5932211862','EUW1_5929934534','EUW1_5930153889','EUW1_5931242804','EUW1_5919621815','EUW1_5918236611'];
const nonUnique = euws.reduce((r, v, i, a) => {
if (!r.includes(v) && a.indexOf(v) !== i) r.push(v);
return r;
}, []);
console.log(nonUnique)
.as-console-wrapper { max-height: 100% !important; top: 0 }

Why are these variables not maintaing value?

I have two problems i cant figure out. When i call GetParams first to get used defined values from a text file, the line of code after it is called first, or is reported to the console before i get data back from the function. Any data gathered in that function is null and void. The variables clearly are being assigned data but after the function call it dissapears.
let udGasPrice = 0;
let udGasLimit = 0;
let udSlippage = 0;
I want to get data from a text file and assign it to variables that need to be global. able to be assigned in a function but used outside it. So above is what i was doing to declare them outside the function. because if i declare them inside, i lose scope. It doesnt seem right to declare with 0 and then reassign, but how else can i declare them gloabaly to be manipulated by another function?
next the code is called for the function to do the work
GetParams();
console.log('udGasPrice = " + udGasPrice );
The code after GetParams is reporting 0 but inside the function the values are right
The data is read and clearly assigned inside the function. its not pretty or clever but it works.
function GetParams()
{
const fs = require('fs')
fs.readFile('./Config.txt', 'utf8' , (err, data) => {
if (err) {
console.error(err)
return;
}
// read file contents into variable to be manipulated
var fcnts = data;
let icnt = 0;
for (var x = 0; x < fcnts.length; x++) {
var c = fcnts.charAt(x);
//find the comma
if (c == ',') {
// found the comma, count it so we know where we are.
icnt++;
if (icnt == 1 ) {
// the first param
udGasPrice = fcnts.slice(0, x);
console.log(`udGasPrice = ` + udGasPrice);
} else if (icnt == 2 ) {
// second param
udGaslimit = fcnts.slice(udGasPrice.length+1, x);
console.log(`udGaslimit = ` + udGaslimit);
} else {
udSlippage = fcnts.slice(udGaslimit.length + udGasPrice.length +2, x);
console.log(`udSlippage = ` + udSlippage );
}
}
}
})
}
Like i said i know the algorithm is poor, but it works.(Im very noob) but why are the variables not retaining value, and why is the code after GetParams() executed first? Thank you for your time.
The code is executed before the GetParams method finishes, because what it does is an asynchronous work. You can see that by the use of a callback function when the file is being read.
As a best practice, you should either provide a callback to GetParams and call it with the results from the file or use a more modern approach by adopting promises and (optionally) async/await syntax.
fs.readFile asynchronously reads the entire contents of a file. So your console.log('udGasPrice = " + udGasPrice ); won't wait for GetParams function.
Possible resolutions are:
Use callback or promise
let udGasPrice = 0;
let udGasLimit = 0;
let udSlippage = 0;
GetParams(() => {
console.log("udGasPrice = " + udGasPrice);
});
function GetParams(callback) {
const fs = require('fs')
fs.readFile('./Config.txt', 'utf8', (err, data) => {
if (err) {
console.error(err)
return;
}
// read file contents into variable to be manipulated
var fcnts = data;
let icnt = 0;
for (var x = 0; x < fcnts.length; x++) {
var c = fcnts.charAt(x);
//find the comma
if (c == ',') {
// found the comma, count it so we know where we are.
icnt++;
if (icnt == 1) {
// the first param
udGasPrice = fcnts.slice(0, x);
console.log(`udGasPrice = ` + udGasPrice);
} else if (icnt == 2) {
// second param
udGaslimit = fcnts.slice(udGasPrice.length + 1, x);
console.log(`udGaslimit = ` + udGaslimit);
} else {
udSlippage = fcnts.slice(udGaslimit.length + udGasPrice.length + 2, x);
console.log(`udSlippage = ` + udSlippage);
}
}
}
callback()
})
}
fs.readFileSync(path[, options]) - it perform same operation in sync - you still need to edit your code accordingly
Also, it's advisable that you don't edit global variables in the function and return updated variables from the function.

How to make template for promise function with Sql queries in JavaScript?

I have few functions which does the same for different objects. For example:
const returnMiscArray = () => {
var i = 0;
var id = 0;
misc = _util.toNull(misc);
const promise = new Promise((resolve, reject) => {
while (Number(order.id[id]) != Number(orderid)) id++;
connection.query(`SELECT * FROM misc WHERE uniqid = ?`, [order.uniqid[id]], function(error, results) {
while (i < results.length) {
misc.uniqid[i] = results[i].uniqid;
misc.id[i] = results[i].id;
misc.count[i] = results[i].count;
misc.cost[i] = results[i].cost;
misc.product[i] = results[i].product;
misc.fcost[i] = results[i].fcost;
i++;
}
resolve(misc);
});
});
return (promise);
}
and
const returnPositionsArray = () => {
var i = 0;
var id = 0;
positions = _util.toNull(positions);
const promise = new Promise((resolve, reject) => {
while (Number(order.id[id]) != Number(orderid)) id++;
connection.query(`SELECT * FROM positions WHERE uniqid = ?`, [order.uniqid[id]], function(error, results) {
while (i < results.length) {
positions.uniqid[i] = results[i].uniqid;
positions.id[i] = results[i].id;
positions.length[i] = results[i].len;
positions.sqr[i] = results[i].sqr;
positions.cost[i] = results[i].cost;
positions.count[i] = results[i].count;
i++;
}
resolve(positions);
});
});
return (promise);
}
I want to make one function which takes object as argument, changes it and returns promise.
thinking of something like that:
const returnArray = (object, cur_order, id) => {
var i = 0;
var j = 0;
object = _util.toNull(object);
var objstr = somevalue; /* CONVERT PASSED OBJECT VARIABLE NAME TO STRING */
const promise = new Promise((resolve, reject) => {
while (Number(cur_order.id[j] != Number(id))) j++;
connection.query(`SELECT * FROM ` + objstr + ` WHERE uniqid = ?`, [cur_order.uniqid[j]], function(error, results) {
while (i < results.length) {
/*
SOMETHING HERE
*/
}
resolve(object);
});
return (promise);
});
}
but I have no idea how can i make it work. I know we can go through object parameters using keys, but how can I do the same for sql results?
Is there a way to make it work?
Ok so you have two functions which handle specific tables. You're already seeing that this is an opportunity to avoid repetition by using abstraction. The question is: what do we abstract?
Look at the two functions and see what is different between the two. Based on what you've written here, what you need to pass in is a table name and a callback that takes a result and it's index i.
But I don't love the code that you've written for a bunch of reasons.
It would probably be better to fetch multiple ids in one SQL call using IN with an array.
Your query callback needs to reject the Promise in the case of an error.
You’re resolving a promise from a loop?
I genuinely don't understand what you are doing with misc.uniqid[i]... Why not just return the results, or a mapped version of them?
Where are these variables order.id and orderid in the first two functions coming from? Can you write the function such that it gets everything it needs from its arguments?

Using data i get from request function in node.JS again until a condition is met

I want to access shopify api using Node.js with request method. I get first 50 items but i need to send the last id of the products i get as a response so it can loop through all the products until we don't have another id (i check that if the last array is not 50 in length.)
So when i get the response of lastID i want to feed that again to the same function until the Parraylength is not 50 or not 0.
Thing is request works asynchronously and i don't know how to feed the same function with the result lastID in node.js.
Here is my code
let importedData = JSON.parse(body);
//for ( const product in importedData.products ){
// console.log(`${importedData.products[product].id}`);
//}
lastID = importedData.products[importedData.products.length-1].id;
let lastIDD = lastID;
console.log(`This is ${lastID}`);
importedData ? console.log('true') : console.log('false');
let Prarraylength = importedData.products.length;
console.log(Prarraylength);
//console.log(JSON.stringify(req.headers));
return lastIDD;
});```
You can use a for loop and await to control the flow of your script in this case.
I'd suggest using the request-native-promise module to get items, since it has a promise based interface, but you could use node-fetch or axios (or any other http client) too.
In this case, to show you the logic, I've created a mock rp which normally you'd create as follows:
const rp = require("request-promise-native");
You can see we're looping through the items, 50 at a time. We're passing the last id as a url parameter to the next rp call. Now this is obviously going to be different in reality, but I believe you can easily change the logic as you require.
const totalItems = 155;
const itemsPerCall = 50;
// Mock items array...
const items = Array.from({ length: totalItems}, (v,n) => { return { id: n+1, name: `item #${n+1}` } });
// Mock of request-promise (to show logic..)
// Replace with const rp = require("request-promise-native");
const rp = function(url) {
let itemPointer = parseInt(url.split("/").slice(-1)[0]);
return new Promise((resolve, reject) => {
setTimeout(() => {
let slice = items.slice(itemPointer, itemPointer + itemsPerCall);
itemPointer += itemsPerCall;
resolve( { products: slice });
}, 500);
})
}
async function getMultipleRequests() {
let callIndex = 0;
let lastID = 0;
const MAX_CALLS = 20;
const EXPECTED_ARRAY_LENGTH = 50;
for(let callCount = 1; callCount < MAX_CALLS; callCount++) {
// Replace with the actual url..
let url = "/products/" + lastID;
let importedData = await rp(url);
lastID = importedData.products[importedData.products.length - 1].id;
console.log("Call #: " + ++callIndex + ", Item count: " + importedData.products.length + ", lastID: " + lastID);
if (importedData.products.length < EXPECTED_ARRAY_LENGTH) {
console.log("Reached the end of products...exiting loop...");
break;
}
}
}
getMultipleRequests();

once("child_added") on non existing node does not fail but timeout

First I'm not sure that there is a real problem but I guess I'll share my reasoning.
I use Firebase as a database / backend for the archiving of all the data from various sensors at home and an UI with cool graphs in hosting. So every 10 minutes I push various data (temperature, humidity, CO2 level, illumination, ...) coming from various rooms. I have almost 3 years of data available (so my base has a lots of nodes)
So my database structure is like that :
root
readings
room_id
GUID
time
temp
hum
lum
For a few years I had a PHP script hosted at home that checked if the latest item inside each readings/room_id has a time value that is not too old (no more than 11 minutes old). I translated it to Firebase cloud function some days ago and I got something like this :
exports.monitor = functions.https.onRequest((req, res) => {
const tstamp = Math.floor(Date.now() / 1000);
var sensors = ["r01", "r02", "r03", "r04", "r05"];
var promiseArray = [];
var result = {};
for (var i = 0; i < sensors.length; i++) {
console.log('Adding promise for ' + sensors[i]);
promiseArray.push(admin.database().ref('/readings/' + sensors[i]).limitToLast(1).once("child_added"));
}
Promise.all(promiseArray).then(snapshots => {
console.log('All promises done : ' + snapshots.length);
res.set('Cache-Control', 'private, max-age=300');
for (var i = 0; i < snapshots.length; i++) {
differenceInMinutes = (tstamp - snapshots[i].val().time) / 60;
result[sensors[i]] = {current: tstamp,
sensor: snapshots[i].val().time,
diff: Math.round(differenceInMinutes * 10) / 10};
if (differenceInMinutes < 11) {
result[sensors[i]]['status'] = "OK";
} else {
result[sensors[i]]['status'] = "KO";
}
}
return res.status(200).json(result);
}).catch(error => {
console.error('Error while getting sensors details', error.message);
res.sendStatus(500);
});
});
The code works well. So my question is : if I add another room ID in the sensors array that does not exists inside "readings" in my database, I thought I'll get an error (failed promise) instead I only got a huge timeout error, I don't want that kind of timeout on Firebase Cloud Functions (to avoid any unwanted cost).
Is that normal ? Is my code wrong ? Do I have to start by getting a shallow snapshot of "readings/room_id" check that it exists and check if has children ?
Thanks a lot for your help.
EDIT : With the help of Frank I fixed my code, here is the revised version :
exports.monitor = functions.https.onRequest((req, res) => {
const tstamp = Math.floor(Date.now() / 1000);
var sensors = ["r01", "r02", "r03", "r04", "r05"];
var promiseArray = [];
var result = {};
for (var i = 0; i < sensors.length; i++) {
console.log('Adding promise for ' + sensors[i]);
promiseArray.push(admin.database().ref('/readings/' + sensors[i]).limitToLast(1).once("value"));
}
Promise.all(promiseArray).then(queryResults => {
console.log('All promises done : ' + queryResults.length);
res.set('Cache-Control', 'private, max-age=300');
queryResults.forEach((snapshots, i) => {
snapshots.forEach((snapshot) => {
var currentData = snapshot.val();
differenceInMinutes = (tstamp - currentData.time) / 60;
result[sensors[i]] = {current: tstamp,
sensor: currentData.time,
diff: Math.round(differenceInMinutes * 10) / 10};
if (differenceInMinutes < 11) {
result[sensors[i]]['status'] = "OK";
} else {
result[sensors[i]]['status'] = "KO";
}
});
});
return res.status(200).json(result);
}).catch(error => {
console.error('Error while getting sensors details', error.message);
res.sendStatus(500);
});
});
a child_added event only fires when there is a child node. If there are not child nodes under the location (or matching the query) it will not fire.
To ensure you also get notified in the condition there are no children, you should listen to the value event:
for (var i = 0; i < sensors.length; i++) {
console.log('Adding promise for ' + sensors[i]);
var query = admin.database().ref('/readings/' + sensors[i]).limitToLast(1).once("value")
promiseArray.push(query);
}
Since a value event may match multiple children in a single snapshot (despite your query only requesting a single child), you will need to loop over the children of the resulting snapshot:
Promise.all(promiseArray).then((queryResults) => {
console.log('All promises done : ' + queryResults.length);
res.set('Cache-Control', 'private, max-age=300');
queryResults.forEach((snapshots) => {
snapshots.forEach((snapshot) => {
differenceInMinutes = (tstamp - snapshot.val().time) / 60;
...

Categories