var rows = [{ a: 1 }, { a: 2 }, { a: 3 }, { a: 4 }];
var results = []; // My results are accumulated here
function runQuery (i) {
if (i >= rows.length) {
console.log('Finished running all queries');
return;
}
var data = rows[i];
console.log('Running query for row', data);
query1.trigger({
additionalScope: {
data: data
},
// You can use the argument to get the data with the onSuccess function
onSuccess: function(data) {
results.push(data) // accumulating results here
runQuery(i + 1);
}
});
}
runQuery(0);
I want to accumulate the results returned from each query I triggered and populate a table widget with those results.
How do I accomplish that?
I tried to refer to the results from myquery by using this in the Data input field {{myquery.data}} of my table widget but it just keeps saying: Value given is null
Hey there @pjc714, and welcome to the community! Thanks for the question, and the detailed explanation. I’m guessing that the problem here is triggering - Run JS Code queries need to be triggered manually. Could you try adding a button under your table that triggers the query and see if that works?
Thanks for your reply Justin, I did as you suggested and triggered my JS Code Query via a DatePicker (of course triggering via Button works as well) and I was able to populate a Table widget by referring to the results returned by my query in the Table widget Data field as {{get_reports_for_date.data}}
This is the get_reports_for_date query I used in case anyone else is trying to do something similar:
// Get the list of report ids
const report_ids = properties.data.Items[0].MapAttribute.report.map((report) => {return report.report})
// Run my analytic_date_range query for a different report id each time
const promises = report_ids.map(id => {
return analytic_date_range.trigger({
additionalScope: {
report_id: id
}
});
});
// Process the results of all the queries executed and combine them into an array to be used in a Table widget
return Promise.all(promises).then(data => {
let reports = [] // The combined results
// Reformat the data as required and 'combine' push the result into the reports array
data.map((result) => {
result.Items.map((item) => {
reports.push({report_id: item.object_id, timestamp: item.timestamp})
})
})
return reports; // This data will be presented in my Table widget
});
The above asynchronous example above worked fine for me but just out of curiosity I still do not understand how you would return data from the synchronous example documented in your code here, can you please explain how to achieve that too.
I modified runQuery() to return a value on completion like so:
if (i >= rows.length) {
console.log('Finished running all queries');
return "Query Finished"; // Return a value on completion
}
and then I tried doing this but it seems like runQuery(0) is running asynchronously so I don't get the value being returned because runQuery(0) had not completed when the value was returned
Glad to hear you got it working @pjc714! I’m not sure what you mean by “how you would return data” - the sync example in the documentation can return data, it’s just a question of how you trigger it.
Hi Justin, in the Promise.all version I am returning the Promise.all as result in the other example in your documentation in the code below please show how I would return a result and use it.
var rows = [{ a: 1 }, { a: 2 }, { a: 3 }, { a: 4 }];
function runQuery (i) {
if (i >= rows.length) {
console.log('Finished running all queries');
return "Hello World"; // Do I return something here?
}
var data = rows[i];
console.log('Running query for row', data);
query1.trigger({
additionalScope: {
data: data
},
// You can use the argument to get the data with the onSuccess function
onSuccess: function(data) {
runQuery(i + 1);
}
});
}
runQuery(0);
If I use the code above and return a value where I said Do I return something here?
and do this
console.log("BEFORE")
let myresult = runQuery(0); console.log(=======> myresult: , myresult)
console.log("AFTER")
myresult is undefined because in the screenshot below its apparent that runQuery() is being run asynchronously because you can see query1 being executed after the AFTER message is logged. So I am not understanding how I can actually use myresult in that case. Can you please show example of just printing out the value of myresult by running the query manually
Without using a Promise or temp state, I don't know of another way to return an aggregated result off the top of my head. The simple/synchronous example here would only be useful for looping through queries where you don't need an aggregated return, I.E. some forms of bulk writes or some other outgoing requests which aren't displayed to the user directly.
To see the results logged sequentially, we'd need to do modify it to something like this:
var rows = [{ a: 1 }, { a: 2 }, { a: 3 }, { a: 4 }];
function runQuery (i) {
if (i >= rows.length) {
console.log('Finished running all queries');
return "Hello World";
}
var data = rows[i];
console.log('BEFORE RUN #'+i);
query1.trigger({
additionalScope: {
data: data
},
// You can use the argument to get the data with the onSuccess function
onSuccess: function(data) {
let myResult = data
console.log(myResult)
console.log("AFTER RUN #"+i)
runQuery(i + 1);
}
});
}
runQuery(0);
If you need to return aggregated data for a loop of .trigger()'s of unknown length (I.E. the query is only known to be complete based the return of one of the individual queries) then you'll probably need to use a temporary state with a default value of [] and .setIn(index, data) to save results as they are returned inside the onSuccess function of the loop. There's an example of doing this with the airtable api here: Keep running REST API requests until all results are returned (Load all rows from an Airtable API)