async function with a foreach loop

Hi guys!

I am getting better but still running into some dead ends with my coding :slight_smile:
This is what I am trying to do:
I have crated a time-table matrix as collection: Gruppenkalender (see pic1).

The idea is that whenever I open the time-table site, the time-table-collection will be cleared, then filled with data from a query function and then finally populates the table on the site.

The code works. I guess it could be a bit more elegant but okā€¦ :blush:
The problem is, that I am running into a time-out:
When the site loads, I am getting maybe 2 of 15 entries.
When I click button10/Neu it executes the function again and I am getting more and more results.
I changed now from a async/await to a .then function but didnā€™t change much.

Button11/Refresh does refresh the dataset connected to the table and is not changing anything. So I guess itā€™s the function.

Frontend:


import wixData from 'wix-data'; 
import {GruppenKalenderReset} from 'backend/Gruppenkalender'; 
import {GruppenKalenderAktuell} from 'backend/Gruppenkalender';  

$w.onReady(async function () { 
$w('#repeater5').expand() 
GruppenKalenderReset().then(() => { 
GruppenKalenderAktuell().then(() => { 
$w('#dataset1').refresh() })}) $w('#dataset1').setFilter(wixData.filter().contains("title", "Montag"))  });  

export function dropdown1_change(event) { 
const filterValue = $w("#dropdown1").value $w('#dataset1').setFilter(wixData.filter().contains("title", filterValue)) }  

export async function button9_click(event) {     
GruppenKalenderReset() .then(() => {     
$w('#dataset1').refresh()}) }  

export async function button10_click(event) {     GruppenKalenderAktuell().then(() => {         
$w('#dataset1').refresh()}) }  

export function button11_click(event) {     
$w('#dataset1').refresh() } 

BackEnd:

import wixData from "wix-data";

export function GruppenKalenderReset() { 
return wixData.query("Gruppenkalender")         
 .limit(500)         
 .find()         
 .then((results) => {             
results.items.forEach((item) => {                 
 item.lyra = null                 
 item.balo = null                 
 item.omego = null                 
 item.amadeo = null                 
 item.pablo = null                 
 item.tymo = null                 
 item.diego = null                 
 item.myro = null 
return wixData.update("Gruppenkalender", item)             
});          
}) } 
 
 

export function GruppenKalenderAktuell() { 
let GruppentrainingP = "b188f84c-bf81-4ab6-86bd-da071f430bf3"     wixData.query("AktuellerBetreuer")         
 .limit(200)         
 .ge('ende', (new Date()))         
 .eq("produkt", GruppentrainingP)         
 .or(             
   wixData.query("AktuellerBetreuer")                  
   .isEmpty('ende')             
   .eq("produkt", GruppentrainingP)         ) 
 .find() // Run the query         
.then(res => {             
res.items.forEach((itemBT) => {  

wixData.query("Gruppentraining")                     
.limit(500)                     
.include("gerate")                     
.eq("aktuellerBetreuer", itemBT._id)                     
.find()                     
.then((results) => {                         
results.items.forEach((item) => { 

let TimeSplitter = item.anfang.split(":");  
let hour = (TimeSplitter[0]);  
let Minutes = (TimeSplitter[1]);  
let Time = hour.padStart(2, '0') + ":" + Minutes.padStart(2, '0')  
let Geraet = item.gerate.title.toLowerCase()  

wixData.query("Gruppenkalender")                                 
.limit(1)                                 
.eq("title", item.title)                                 
.eq("anfang", Time) 
.find()                                 
.then((results2) => { 
 let data = results2.items[0]  //console  //  let data = results2.  
 if (Geraet === "lyra") { data.lyra = item.kunde }  
 if (Geraet === "balo") { data.balo = item.kunde }  
 if (Geraet === "omego") { data.omego = item.kunde }  
 if (Geraet === "amadeo") { data.amadeo = item.kunde }  
 if (Geraet === "pablo") { data.pablo = item.kunde }  
 if (Geraet === "tymo") { data.tymo = item.kunde }  
 if (Geraet === "diego") { data.diego = item.kunde }  
 if (Geraet === "myro") { data.myro = item.kunde }  //console.log(data) 
  wixData.update("Gruppenkalender", data)                                         .then((results3) => {  
 let item3 = results3; //see item below                                                                                     
  })                                         
 .catch((err) => {  let errorMsg = err;                                         });                                 
  })                         
 })                     
  })             
 })         
  }) } 

Any idea how I get this baby workin and more solid?

I havenā€™t gone over your code, but at first glance I can see you have many nesting promises and that a recipe for mistakes. You should cancel the nesting and use ā€œreturnā€ to chain them. Itā€™ll make the code more readable and easy to look at.
And example for what I mean:

export function GruppenKalenderAktuell() { 
let GruppentrainingP = "b188f84c-bf81-4ab6-86bd-da071f430bf3";
return  wixData.query("AktuellerBetreuer")         
 .limit(200)         
 .ge('ende', (new Date()))         
 .eq("produkt", GruppentrainingP)         
 .or(             
   wixData.query("AktuellerBetreuer")                  
   .isEmpty('ende')             
   .eq("produkt", GruppentrainingP)         ) 
 .find() // Run the query 
})        
.then(res => {
let itemsQuery = res.items.map(itemBT => {
return wixData.query("Gruppentraining")                     
.limit(500)                     
.include("gerate")                     
.eq("aktuellerBetreuer", itemBT._id)                     
.find()
})
return Promise.all(itemsQuery) 
})
 .then((results) => { 
//etc...

@J.D. Thanks a lot for your support. I was trying around different options and split everything in different backend functions. I was also able to avoid one foreach loop in order to speed up.
Still I have the same result but at least I could narrow it down to the last function.

I pass a simple query result to the last function:
Still I need to execute this function many times to get the full result written into the ā€œGruppenkalenderā€ collection. So I guess itā€™s a async problem but I canā€™t figure out what it is.
Please help!

 export async function GruppenKalender(results) {
 let FE  
 results.items.forEach((item) => {
 let TimeSplitter = item.anfang.split(":");  
 let hour = (TimeSplitter[0]);  
 let Minutes = (TimeSplitter[1]);  
 let Time = hour.padStart(2, '0') + ":" + Minutes.padStart(2, '0')  
 let Geraet = item.gerate.title.toLowerCase()  
       
 wixData.query("Gruppenkalender")             
 .limit(1)             
 .eq("title", item.title)             
 .eq("anfang", Time) //item.anfang.toLocaleString()             
 .find()             
 .then((results2) => { 
 
  let data = results2.items[0] 
   
  if (Geraet === "lyra") { data.lyra = item.kunde }  
  if (Geraet === "balo") { data.balo = item.kunde }  
  if (Geraet === "omego") { data.omego = item.kunde }  
  if (Geraet === "amadeo") { data.amadeo = item.kunde }  
  if (Geraet === "pablo") { data.pablo = item.kunde }  
  if (Geraet === "tymo") { data.tymo = item.kunde }  
  if (Geraet === "diego") { data.diego = item.kunde }  
  if (Geraet === "myro") { data.myro = item.kunde }                 
 
 wixData.update("Gruppenkalender", data)             
  
  }) 
    })     
  FE = "Done"  
  return FE 
  }
  
 
 

I donā€™t really know what youā€™re trying to achieve and how, but Iā€™ll say again - I think itā€™s not a good idea to use nesting promises. Itā€™s hard to read and it can lead to mistakes.
Also I think you should try to avoid running promises with forEach() method, itā€™s a complicated logics. Why wonā€™t you use Promise.all() on all these promises and then map the results and use bulkUpdate() to update them all at once?

  • If you run too many queries at the same time itā€™s not going to work, no matter which method youā€™re using (so maybe try to rearrange your data differently).
1 Like

The problem with any foreach loop like this is usually not that the loop is slow, itā€™s almost always too fast for whatā€™s going on inside, in this case the fact that youā€™re doing a query and update.

JS is asynchronous in the way it begins events, but you have to ensure that if they overlap they donā€™t mess things up, or else that they donā€™t overlap. Promises are an OK way of doing this, but not particularly spectacular; async await is only as good as the person who wrote the function being called is good at accounting for stuff.

So for heavy duty work, you need a more reliable solutionā€¦maybe something like this or there are others:

let i = 0;
foo(myArr);

function foo(cloneArr) {
    bar(cloneArr[i], i, () => { i++ });
    if (i < cloneArr.length) foo(myArr);
}

function bar(item, iteration, callback) {
    //do stuff that needs to be done
    if (/*right response and/or event completed*/) callback();
}

Hi J.D. many thanks for your help again! It took a bit to make myself familiar with Promise.all() concept. But since I understand it, itā€™s brilliant and solid.
One level up thanks to you!
J Florian

1 Like