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).

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