How to sum the results of a fetch using multiple functions? - javascript

I am working with OpenWeatherMapAPI to calculate the sum of precipitation for the previous 5 days. To do this I have 5 async functions with api calls using the fetch api. The data received, that concerns me, is the hourly historic weather data spanning a 24 hour period. Full code bellow. The json response is stored to a constant (Ex.const histData1) where it is then iterated through to sum all of one values over that given 24 hour period. Note: humidity is used as a proof of concept because it hasnt rained here in awhile
for (var i in histData1.hourly){
total1 += histData1.hourly[i].humidity;
};
When I send the resulting value, total1, to the console I receive the expected results.
My trouble is coming when trying to add all of these results together i.e. total1 + total2 + total3 + total4 + total5.
One solution I thought might work was returning the total[1,2,3,4,5] variable at each function and then summing them. Ex.
var rainTotals = getData1() + getData2() + getData3() + getData4() + getData5()
console.log(rainTotals)
This resulted in the following output: [object Promise][object Promise][object Promise][object Promise][object Promise] so it appears to be a datatype issue.
Can anyone shed light as to adding all of the humidity values up from the five separate functions. Feel free to roast my code, I'm pretty new at this.
Thanks!
//WORKS Provies a json of hourly weather data for (1)24 hr period starting 5 days ago.
const fiveDaysAgo = Math.floor((Date.now() / 1000)-432000);
const fivedayURL = "http://api.openweathermap.org/data/2.5/onecall/timemachine?lat=29.8833&lon=-97.9414&dt=" + fiveDaysAgo +"&appid="
async function getData5(){
const response5 = await fetch(fivedayURL)
const histData5 = await response5.json();
var total5 = 0
for (var i in histData5.hourly){
total5 += histData5.hourly[i].humidity;
};
console.log(total5);
return total5;
}
getData5();
const fourDaysAgo = Math.floor((Date.now() / 1000)-345600);
const fourdayURL = "http://api.openweathermap.org/data/2.5/onecall/timemachine?lat=29.8833&lon=-97.9414&dt=" + fourDaysAgo +"&appid=5ffab1cda2c6b2750c78515f41421805"
async function getData4(){
const response4 = await fetch(fourdayURL)
const histData4 = await response4.json();
var total4 = 0;
for (var i in histData4.hourly){
total4 += histData4.hourly[i].humidity
};
console.log(total4);
return total4;
}
getData4();
const threeDaysAgo = Math.floor((Date.now() / 1000)-259200);
const threedayURL = "http://api.openweathermap.org/data/2.5/onecall/timemachine?lat=29.8833&lon=-97.9414&dt=" + threeDaysAgo +"&appid=5ffab1cda2c6b2750c78515f41421805"
async function getData3(){
const response3 = await fetch(threedayURL);
const histData3 = await response3.json();
var total3 = 0;
for (var i in histData3.hourly){
total3 += histData3.hourly[i].humidity;
};
console.log(total3);
return total3;
}
getData3();
const twoDaysAgo = Math.floor((Date.now() / 1000)-172800);
const twodayURL = "http://api.openweathermap.org/data/2.5/onecall/timemachine?lat=29.8833&lon=-97.9414&dt=" + twoDaysAgo +"&appid=5ffab1cda2c6b2750c78515f41421805"
async function getData2(){
const response2 = await fetch(twodayURL);
const histData2 = await response2.json();
var total2 = 0;
for (var i in histData2.hourly){
total2 += histData2.hourly[i].humidity;
};
console.log(total2);
return total2;
}
getData2();
const oneDaysAgo = Math.floor((Date.now() / 1000)-86400);
const onedayURL = "http://api.openweathermap.org/data/2.5/onecall/timemachine?lat=29.8833&lon=-97.9414&dt=" + oneDaysAgo +"&appid=5ffab1cda2c6b2750c78515f41421805"
async function getData1(){
const response1 = await fetch(onedayURL);
const histData1 = await response1.json();
var total1 = 0;
for (var i in histData1.hourly){
total1 += histData1.hourly[i].humidity;
};
console.log(total1);
return total1;
}
getData1();
var rainTotals = getData1() + getData2() + getData3() + getData4() + getData5()
console.log(rainTotals)//returns [object Promise][object Promise][object Promise][object Promise][object Promise]

There are a couple things happening here. Firstly, to answer your question, because your getDataX functions are declared asynchronous, they return Promises that will eventually either resolve or reject with the actual values that you're looking for.
When working with Promises, you need sum the total values after all of these promises have resolved.
Second, you have a bit of duplication in your code. You'll notice that there is very little difference between the innards of your getDataX function. To simplify this, you can extract the differences as function parameters, and encapsulate all the same code within one function.
This would result in an implementation like below:
function getDaysAgo(days) {
return Math.floor((Date.now() / 1000) - (86400 * days))
}
async function getDataForDaysAgo(days) {
let daysAgo = getDaysAgo(days)
const apiURL = `http://api.openweathermap.org/data/2.5/onecall/timemachine?lat=29.8833&lon=-97.9414&dt=${daysAgo}&appid=5ffab1cda2c6b2750c78515f41421805`
const apiResponse = await fetch(apiURL)
const responseJson = await apiResponse.json()
var total = 0
responseJson.hourly.forEach(hour => {
total += hour.humidity
});
console.log(`getDataForDaysAgo(${days}) returns ${total}`)
return total
}
async function getDataSums() {
var data1 = await getDataForDaysAgo(5)
var data2 = await getDataForDaysAgo(4)
var data3 = await getDataForDaysAgo(3)
var data4 = await getDataForDaysAgo(2)
var data5 = await getDataForDaysAgo(1)
return data1 + data2 + data3 + data4 + data5;
}
getDataSums().then(result => {
console.log(result)
})

Async functions always returns a promise.
What you can do is to use Promise.all to aggregate them into one array.
Promise.all([getData1(), getData2(), getData3(), getData4(), getData5()]).then((values) => {
var sum = 0;
for(var i=0; i<values.length; i++){
sum += values[i];
}
console.log(sum);
});
Source : Async Functions

You can use await to get the result of async function.
var rainTotals = await getData1() + await getData2() + await getData3() + await getData4() + await getData5();

Async function delays because it wait for await. 'return' give data immediatly so that's why data give empty object(when console.log(getData1()) only empty objects returned). So getding total data should be awaited. 'total' data in each getData function was pushed into an array. Each getData function get await in asyncAll function to log array at once.
// Data array
let arr = [];
//WORKS Provies a json of hourly weather data for (1)24 hr period starting 5 days ago.
const fiveDaysAgo = Math.floor((Date.now() / 1000)-432000);
const fivedayURL = "http://api.openweathermap.org/data/2.5/onecall/timemachine?lat=29.8833&lon=-97.9414&dt=" + fiveDaysAgo +"&appid=5ffab1cda2c6b2750c78515f41421805"
async function getData5(){
const response5 = await fetch(fivedayURL)
const histData5 = await response5.json();
var total5 = 0
for (var i in histData5.hourly){
total5 += histData5.hourly[i].humidity;
};
console.log(total5);
await arr.push(total5);
return total5;
}
getData5();
const fourDaysAgo = Math.floor((Date.now() / 1000)-345600);
const fourdayURL = "http://api.openweathermap.org/data/2.5/onecall/timemachine?lat=29.8833&lon=-97.9414&dt=" + fourDaysAgo +"&appid=5ffab1cda2c6b2750c78515f41421805"
async function getData4(){
const response4 = await fetch(fourdayURL)
const histData4 = await response4.json();
var total4 = 0;
for (var i in histData4.hourly){
total4 += histData4.hourly[i].humidity
};
console.log(total4);
await arr.push(total4);
return total4;
}
getData4();
const threeDaysAgo = Math.floor((Date.now() / 1000)-259200);
const threedayURL = "http://api.openweathermap.org/data/2.5/onecall/timemachine?lat=29.8833&lon=-97.9414&dt=" + threeDaysAgo +"&appid=5ffab1cda2c6b2750c78515f41421805"
async function getData3(){
const response3 = await fetch(threedayURL);
const histData3 = await response3.json();
var total3 = 0;
for (var i in histData3.hourly){
total3 += histData3.hourly[i].humidity;
};
console.log(total3);
await arr.push(total3);
return total3;
}
getData3();
const twoDaysAgo = Math.floor((Date.now() / 1000)-172800);
const twodayURL = "http://api.openweathermap.org/data/2.5/onecall/timemachine?lat=29.8833&lon=-97.9414&dt=" + twoDaysAgo +"&appid=5ffab1cda2c6b2750c78515f41421805"
async function getData2(){
const response2 = await fetch(twodayURL);
const histData2 = await response2.json();
var total2 = 0;
for (var i in histData2.hourly){
total2 += histData2.hourly[i].humidity;
};
console.log(total2);
await arr.push(total2);
return total2;
}
const oneDaysAgo = Math.floor((Date.now() / 1000)-86400);
const onedayURL = "http://api.openweathermap.org/data/2.5/onecall/timemachine?lat=29.8833&lon=-97.9414&dt=" + oneDaysAgo +"&appid=5ffab1cda2c6b2750c78515f41421805"
async function getData1(){
const response1 = await fetch(onedayURL);
const histData1 = await response1.json();
var total1 = 0;
for (var i in histData1.hourly){
total1 += histData1.hourly[i].humidity;
};
console.log(total1);
//Push data after data asynced
await arr.push(total1);
return total1;
}
//Moved getData function to asyncAll function.
var rainTotals = [];
// Awaited for getData functions, logged total data.
async function asyncAll() {
await getData1();
await getData2();
await getData3();
await getData4();
await getData5();
await console.log(arr.join(', '), 'async');
}
asyncAll();

Related

Async await with Fetch

my fetch works perfectly with .then, but i want to step it up a notch by using async and await. It should wait for all 5 API calls, and then place the answer, instead, it shows answer on every API call
async function getPhotosFromAPI() {
for (let i = 1; i <= 5; i++) {
let albums = await fetch(
`https://jsonplaceholder.typicode.com/photos/?albumId=${i}`
);
let result = await albums.json();
let res = `<div class="album${i}"></div>`;
document.querySelector(".display-images").innerHTML += res;
for (let j = 1; j <= 5; j++) {
document.querySelector(
`.album${i}`
).innerHTML += `<img src="${result[j].url}"/>`;
}
}
console.log(result);
}
async function showPhotos() {
await getPhotosFromAPI();
document.getElementById("#loader").style.display = "none";
}
showPhotos();
document.getElementById("img").style.display = "block";
for (let i = 1; i <= 5; i++) {
fetch(`https://jsonplaceholder.typicode.com/photos/?albumId=${i}`)
.then((response) => response.json())
.then((json) => {
document.getElementById("img").style.display = "none";
const display = document.querySelector(".display-images");
const albumNo = document.querySelector(".album-no");
// document.getElementById('img').style.display = "block";
// document.getElementById('img').style.display = "none";]
display.innerHTML += `<div class="album-${i}>`;
for (let z = 1; z <= 5; z++) {
display.innerHTML += `<img id="img" alt="pic-from-album${json[i].albumId}" src="${json[z].url}"/>`;
}
display.innerHTML += `<div>`;
});
}
You should use a concurrent way of fetching like Promise.all to avoid round-trips
async function getPhotosFromAPI() {
let albums = await Promise.all(
Array(5).fill().map((elem, index) =>
fetch(`https://jsonplaceholder.typicode.com/photos/?albumId=${index+1}`)
)
)
let results = await Promise.all(
albums.map(album => album.json())
)
return results
}
//Display
You're asking for the code to wait until each fetch finishes by using await on fetch's return value (then again on the return value of json) in your loop. So it will do just that: wait until that request is complete before moving on to the next loop iteration.
If you don't want to do that, you need to start each fetch one after another and then wait for them all to complete. I'd probably break out the work for just one of them into a function, then call it five times, building an array of the promises it returns, then await Promise.all(/*...*/) those promises, something along these lines:
document.getElementById("img").style.display = "block";
// Fetch one item
const fetchOne = async (i) => {
const response = await fetch(`https://jsonplaceholder.typicode.com/photos/?albumId=${i}`);
if (!response.ok) {
throw new Error(`HTTP error ${response.status}`);
}
const data = await response.json();
document.getElementById("img").style.display = "none";
const display = document.querySelector(".display-images");
const albumNo = document.querySelector(".album-no");
// document.getElementById('img').style.display = "block";
// document.getElementById('img').style.display = "none";]
display.innerHTML += `<div class="album-${i}>`;
for (let z = 1; z <= 5; z++) {
display.innerHTML += `<img id="img" alt="pic-from-album${data[i].albumId}" src="${data[z].url}"/>`;
}
display.innerHTML += `<div>`;
};
// ...
await Promise.all(Array.from({length: 5}, (_, i) => fetchOne(i + 1)));
// All done
(I took the version with .then as my starting point for the above, since the two versions in your question were so different and you said the one with .then worked... Also note that I renamed the variable json to data, since it doesn't contain JSON [it's not a string], it contains the result of parsing JSON.)

Cloud function does not write second argument to Firebase

I have written a cloud function that runs every 5 minutes on my Firebase app. In essence, the function gathers trends data from the Google Trends website and parses the JSON into a variable.
After doing so I want to then connect to the Twitter API and search for tweets using the trending topics fetched in the first part.
My Issue seems to lie with the second part. It fetches the data but the remainder of the function does not wait for the result before writing to Firebase.
I have tried two different methods but both don't seem to work as intended. I am struggling to understand how the function should wait for the second part to gather and store the information before writing to Firebase.
Method 1
exports.callTo = functions.pubsub.schedule("5 * * * *").onRun((context) => {
let searchTrends;
const ts = Date.now();
const dateOb = new Date(ts);
const date = dateOb.getDate();
const month = dateOb.getMonth() + 1;
const year = dateOb.getFullYear();
const twitterTrends = [];
googleTrends.dailyTrends({
trendDate: new Date(year + "-" + month + "-" + date),
geo: "CA",
}, function(err, res) {
if (err) {
functions.logger.error(err);
} else {
searchTrends = JSON.parse(res).default.trendingSearchesDays[0]
.trendingSearches;
functions.logger.info(searchTrends);
for (let i = 0; i < searchTrends.length; i++) {
functions.logger.log(searchTrends[i].title.query);
T.get("search/tweets", {q: searchTrends[i].title.query, count: 1},
function(err, data, response) {
if (err) {
functions.logger.error(err);
}
functions.logger.info("Twitter data" +
JSON.stringify(data.statuses));
twitterTrends[i] = JSON.stringify(data.statuses);
});
}
const dbRef = admin.database().ref("searchTrends");
dbRef.set({google: searchTrends, twitter: twitterTrends});
}
});
});
Method 2
exports.callTo = functions.pubsub.schedule("5 * * * *").onRun((context) => {
let searchTrends;
const ts = Date.now();
const dateOb = new Date(ts);
const date = dateOb.getDate();
const month = dateOb.getMonth() + 1;
const year = dateOb.getFullYear();
const twitterTrends = [];
async function getTrends(){
googleTrends.dailyTrends({
trendDate: new Date(year + "-" + month + "-" + date),
geo: "CA",
}, function(err, res) {
if (err) {
functions.logger.error(err);
} else {
searchTrends = JSON.parse(res).default.trendingSearchesDays[0]
.trendingSearches;
functions.logger.info(searchTrends);
}
});
await getTwitterTrends();
}
async function getTwitterTrends(){
for (let i = 0; i < 1; i++) {
functions.logger.log(searchTrends[i].title.query);
T.get("search/tweets", {q: searchTrends[i].title.query, count: 1},
function(err, data, response) {
if (err) {
functions.logger.error(err);
} else {
functions.logger.info("Twitter data" +
JSON.stringify(data.statuses));
twitterTrends[i] = JSON.stringify(data.statuses);
}
});
}
return "done";
}
const dbRef = admin.database().ref("searchTrends");
dbRef.set({google: searchTrends, twitter: twitterTrends});
});
After checking your function it looks like a Promises issue. The reason you are seeing only the searchTrends data in Firestore is because the Firestore reference and upload is being done inside the callback for the dailyTrends method (taking for reference the method 1 code). However this does not wait for each request to the Twitter API to be resolved before writing to Firestore.
Based on the documentation for twit (which seems to be the wrapper you are using), it also supports standard promises. You could add each promise to an array, and then use Promise.all() to wait until they are all resolved to then write the data into Firestore. It would look something like this (which I haven’t tested since I don’t have Twitter API access).
exports.callTo = functions.pubsub.schedule("5 * * * *").onRun((context) => {
const ts = Date.now();
const dateOb = new Date(ts);
const date = dateOb.getDate();
const month = dateOb.getMonth() + 1;
const year = dateOb.getFullYear();
let searchTrends;
const twitterTrends = [];
const twPromises = [];
googleTrends.dailyTrends({
trendDate: new Date(year + "-" + month + "-" + date),
geo: "CA",
}, function(err, res) {
if (err) {
functions.logger.error(err);
} else {
searchTrends = JSON.parse(res).default.trendingSearchesDays[0]
.trendingSearches;
functions.logger.info(searchTrends);
for (let i = 0; i < searchTrends.length; i++) {
functions.logger.log(searchTrends[i].title.query);
twPromises.push(T.get("search/tweets", {q: searchTrends[i].title.query, count: 1})); // adds promises to the array
}
Promise.all(twPromises).then((responses) => { // runs when all promises from the array are resolved
responses.forEach((response) => {
twitterTrends.push(JSON.stringify(response.statuses));
})
const dbRef = admin.database().ref("searchTrends");
dbRef.set({google: searchTrends, twitter: twitterTrends});
})
}
});
});

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();

Getting undefined error from postgresql query in NodeJs

I'm trying to execute query and use some rows of the results.
When I tried this code:
const pg = require('pg')
var Log = require('fancy-log');
var jsonPath = require('jsonpath');
var validator = require('validator');
var isEmpty = require('is-empty-array')
const argv = require('yargs').argv
require('custom-env').env(argv.env)
var db = require('./db');
var checker = require('./checklist')
let txn_id;
var param = []
//////////////////////////////////// DB Connection Block & executeQuery ////////////////////////////////////
var config = {
user: process.env.DB_USER,
password: process.env.DB_PASS,
host: process.env.DB_HOST,
port: process.env.DB_PORT,
database: process.env.DB,
max: 10, // max number of clients in the pool
idleTimeoutMillis: 30000 // how long a client is allowed to remain idle before being closed
}
const pool = new pg.Pool(config)
async function query(q,param) {
const client = await pool.connect()
let res
try {
await client.query('BEGIN')
try {
res = await client.query(q, param)
await client.query('COMMIT')
Log("Connection succeed.")
} catch (err) {
await client.query('ROLLBACK')
throw err
}
} finally {
client.release()
}
return res
}
//////////////////////////////////// DB Connection Block & executeQuery ////////////////////////////////////
//client.getConnection();
//db.main()
//db.print()
async function executeQuery(queryParam, conditions) {
try {
const { rows, rowCount } = await query(queryParam, conditions)
txn_id = await rows[Math.floor(Math.random() * rowCount + 1)].txn_id
Log("Related txn_id: " + txn_id)
} catch (err) {
console.log('Database ' + err)
}
}
executeQuery("SELECT * from table_name",[])
I got this error all the time:
Database TypeError: Cannot read property 'txn_id' of undefined
My first usecase is working two different js file like db.js for connection and query function, export it and use it in main.js. Unfortunately, I couldn't get success. Probably, I don't understand fully of await usage.
Thanks for any idea in advance!
EDIT: This is main goal. I want to seperate all my logics.
db.js
const pg = require('pg')
var Log = require('fancy-log');
const argv = require('yargs').argv
require('custom-env').env(argv.env)
//var db = function(){};
let txn_id;
var param = []
var config = {
user: process.env.DB_USER,
password: process.env.DB_PASS,
host: process.env.DB_HOST,
port: process.env.DB_PORT,
database: process.env.DB,
max: 10, // max number of clients in the pool
idleTimeoutMillis: 30000 // how long a client is allowed to remain idle before being closed
}
const pool = new pg.Pool(config)
async function query(q,param) {
const client = await pool.connect()
let res
try {
await client.query('BEGIN')
try {
res = await client.query(q, param)
await client.query('COMMIT')
Log("Connection succeed.")
} catch (err) {
await client.query('ROLLBACK')
throw err
}
} finally {
client.release()
}
return res
}
async function executeQuery(queryParam, conditions) {
try {
const { rows, rowCount } = await query(queryParam,conditions)
txn_id = await rows[Math.floor(Math.random() * rowCount + 1)].txn_id
Log("Related txn_id: " + txn_id)
} catch (err) {
console.log('Database ' + err)
}
}
module.exports = {
executeQuery
}
main.js
const pg = require('pg')
var Log = require('fancy-log');
var jsonPath = require('jsonpath');
var validator = require('validator');
var isEmpty = require('is-empty-array')
const argv = require('yargs').argv
require('custom-env').env(argv.env)
var db = require('./db');
var checker = require('./checklist')
async function foo(){
await db.executeQuery("SELECT * from table_name",[])
}
foo()
Also same error here:
Database TypeError: Cannot read property 'txn_id' of undefined
You probably solved this already, but since there are no answers, in case someone needs help with this in the future.
TL;DR: You have to remove +1 from txn_id = await rows[Math.floor(Math.random() * rowCount + 1)].txn_id.
rows is an array of length N (N rows found in table_name) with indices from 0 to N-1, and rowCount equals (in this case) rows.length; and since:
1) 0 <= Math.random() < 1
2) 0 <= Math.random() * rowCount < N
3) 1 <= Math.random() * rowCount + 1 < N+1
4) 1 <= Math.floor(Math.random() * rowCount + 1) < N+1 (only natural numbers now)
then Math.floor(Math.random() * rowCount + 1) produces indeces from 1 to N, which is why sometimes (in case of N) rows[Math.floor(Math.random() * rowCount + 1)] equals undefined.
Also, await is not needed here: await rows[Math.floor(Math.random() * rowCount)]; you already awaited for the query to finish here const { rows, rowCount } = await query(queryParam,conditions).
Only place await in front of an expression which returns a Promise, otherwise it's doing nothing. (suggested)

Issue structuring a promise in a loop

I am struggling with getting this resolved, as I am new to Promises.
I need to first read both the Summative and Formative from Firebase before I can determine the StudentPlacement
The way the code below, provides null as the StudentPlacement snapshot.val(), as it is not waiting for the x and y values.
exports.boxScoresUpdate = functions.database.ref('/Tests/{id}/TestScores').onWrite(event => {
let testScr = 0;
for (let i = 1; i <= section; i++) {
//
testScr += parseInt(nValue[i]);
var xIndex = 0;
var yIndex = 0;
admin.database().ref('TestScores').child(data.key).child('Summative').child(i).once("value").then(x => {
xIndex = x.val();
});
admin.database().ref('TestScores').child(data.key).child('Formative').child(i).once("value").then(y => {
yIndex = y.val();
});
admin.database().ref('StudentPlacement').child(data.key).child(xIndex + ":" + yIndex).once("value", snapshot => {
// SnapShot
console.log("Student Placement is: ", snapshot.val());
});
}
}
Can anyone please help me structure the trigger!?
You're waiting for both functions to finish before executing the next bit of code. Look into Promise.all.
for (let i = 1; i <= section; i++) {
const xIndexRef = admin.database().ref('TestScores').child(data.key).child('Summative').child(i).once("value");
const yIndexRef = admin.database().ref('TestScores').child(data.key).child('Formative').child(i).once("value");
Promise.all([xIndexRef, yIndexRef])
.then(results => {
const xSnapshot = results[0];
const ySnapshot = results[1];
return admin.database().ref('StudentPlacement').child(data.key).child(xSnapshot.val() + ":" + ySnapshot.val()).once("value");
})
.then(snapshot => {
console.log("Student Placement is: ", snapshot.val());
});
}
Promise.all waits for both xIndexRef and yIndexRef to complete their execution.
Once executed the results are returned into a thenable object.
You can access the results and complete your execution.

Categories