“Een goede app moet niet veel data verzamelen.”
Naar aanleiding van een verzoek van een klant discussieerden we over deze ongeschreven regel. Nadat we uren bezig waren geweest om de beste oplossing voor hen te vinden, besloten we tegen de stroom in te gaan. Toch moesten we de juiste balans vinden tussen het uploaden van alle data vanaf het begin enerzijds, en gebruikers een paar keer per uur kleinere batches data laten opvragen anderzijds.
Deze oefening gaf ons een goed inzicht in hoe je best omgaat met grote datasets. We delen onze oplossing graag met jullie.
Het uitgangspunt
Laten we beginnen met een alternatieve aanpak van mijn collega Hans Santens. Hij schreef een interessant artikel over het parsen van grote datasets met Power Automate dat zeker de moeite waard is om te lezen. Hij legt uit hoe je Power Automate kan gebruiken om grote datasets (+2K) te verzamelen en in een Power App te plaatsen.
Ik nam dezelfde route tijdens de ontwikkeling, maar koos toen voor een andere aanpak om verder te gaan. Uiteindelijk werd de Power Automate oplossing langzamer, niet alleen door de hoeveelheid data, maar ook door elke extra kolom die aan de query werd toegevoegd.
We kwamen een aantal moeilijke issues tegen die we wilden oplossen:
- Extra korte tijd voor praten en ontvangen van en naar PowerAutomate naast de uitvoeringstijd van PowerAutomate. Elke seconde telt 😊
- Alles werd langzamer met elk extra record en kolom omdat de geretourneerde Json per kolom getypecast moest worden (in een lus).
- Er waren veel regels code nodig om alle velden te typecasten.
- Het was moeilijk om met complexere datatypes te werken.
- Er was extra onderhoud van het PowerAutomate script nodig.
- We moesten nog steeds aparte collecties maken die overeenkwamen met de velden in SharePoint voor patchingdoeleinden.
Dat wil niet zeggen dat de aanpak van mijn collega het overwegen niet waard is. Het is zeker een juiste oplossing voor het verzamelen van grotere datasets.
De aanpak waar ik me hier op wil richten werkt alleen in Power Apps en verzamelt +30K records in een enkele verzameling. De netwerksnelheid kan de snelheid veranderen die nodig is om de data te verzamelen. Ik raad je aan om voor de zekerheid de applicatie opnieuw te starten tijdens een pauze.
Hoe het werkt
Voor mijn oplossing heb ik een lus gebruikt die maximaal 2K records krijgt (de standaard maximumlimiet voor een verzameling) voor elke run van de lus.
Eerst probeerde ik de lijst te filteren op basis van de ID van elk item. Je hebt een tussenvariant nodig of een groter/kleiner equivalent, maar de ‘>=’ en ‘<=’ geven je een delegatie waarschuwing. Dus ging ik verder met zoeken, niet bereid om het risico te nemen dat er data zouden ontbreken.
Ik besloot mijn eigen integer waarde kolom per record toe te voegen. Alle records met een ID < 2000 kregen 1, de volgende groep van 2K records kreeg 2, enzovoort. En dat is de sleutel tot het oplossen van dit probleem – en tegelijkertijd het verkleinen ervan.
Met deze integer waarde kan je ‘=’ gebruiken, waardoor je geen delegatiewaarschuwing krijgt. Je moet de waarde echter berekenen wanneer je de record aanmaakt via een extra patch/edit.
Je hebt hier twee opties:
- Kijk naar de laatste ID, ervan uitgaande dat gebruikers niet tegelijkertijd records toevoegen, en stel de volgende ID in.
- Maak de record aan en vraag naar de nieuw toegevoegde ID. Voeg de integer waarde toe na het aanmaken (extra stap om de record bij te werken).
Aan de slag
Er zijn twee belangrijke topics waarop we moeten focussen:
- Ervoor zorgen dat elke record met de juiste integerwaarde wordt opgeslagen.
- De data ophalen via de integerwaarde via lussen.
In PowerApps haalt een verzameling maximaal 2K records op. Door ‘Collect’ te gebruiken na ‘ClearCollect’ kan je eenvoudig meer rijen toevoegen aan dezelfde verzameling.
Bijvoorbeeld:
- 2K customers in London
- ClearCollect(colCustomers, filter(Customers, City=’London’))
- 3K customers in Paris
- Collect(colCustomers, filter(Customers, City=’Paris’))
- Totaal = 2.5K rijen in colCustomers
Nu we dit weten, moeten we een manier vinden om dit zo vaak als nodig te herhalen.
De data opvragen
Om de data te krijgen, moeten we de hoogste gehele getalswaarde in de lijst weten en een lus maken van 1 tot dat getal. Ik heb mijn kolom ‘dg’ (DataGrouping) genoemd.
Je zal zien dat ik sorteer op ID (aflopend) en vraag om de eerste ‘dg’-waarde, die de grootste is op basis van de sortering. Het gebruik van ‘Max’ voor ‘dg’ gaf ook een delegatiewaarschuwing.
Set( varLastDG, First( Sort( <SP List>, ID, SortOrder.Descending ) ).dg )
Maak nu de lus (ForAll). Gebruik ‘Sequence’ om een lijst met getallen te maken van 1 tot varLastDG.
ForAll( Sequence(varLastDG), Collect( <collection name>, Filter( <SP list>, dg = Value, Department = “R&D”, Active = true ) ) )
De extra filters op ‘Department’ of ‘Active’ kunnen het aantal geretourneerde records verminderen en het hele proces versnellen. Niet elke lus zal precies 2K records opleveren, misschien wel helemaal geen.
Voeg je verzameling toe aan een grid om het resultaat te visualiseren. Dat is alles wat je nodig hebt om je data te verzamelen!
Nu moet je ervoor zorgen dat elke record de juiste integer waarde krijgt. Je moet er ook voor zorgen dat je dezelfde waarde niet meer dan 2K keer toevoegt.
Patch je integer waarde
Voor deze oplossing patch ik een nieuwe record op de standaard manier. Zo weet je echter niet 100% zeker welk ID de record zal krijgen. Daarom wordt de nieuw aangemaakte record opgeslagen in een variabele. Je kan de nieuwe ID uit deze variabele halen en dan het record patchen (bijwerken) met die waarde.
Gebruik een patch comment om een record toe te voegen of bij te werken. Sla het resultaat van de patch-actie op in een variabele en haal de ID op. Voor een update hoef je de integer waarde niet te patchen. De record heeft zijn integer waarde wanneer je de record aanmaakt. Het getal verandert nooit.
Patch een nieuwe record
// Maak de record en sla die op in een variabele
Set( varSavedRecord, Patch( <SP List>, Defaults(<SP List>) { Title: txtWPNumber.Text, ....... } ) );
// Verkrijg de ID van de record die in de patch wordt gebruikt
Set( varPatchedID, varSavedRecord.ID );
// Bereken je integer value
Set( varNewDG, Int(varPatchedID / 2000) + 1 );
// Patch de integer waarde in de record (niet nodig bij het bijwerken van een record omdat het zijn ID heeft gekregen toen je de record aanmaakte)
If( varEditState = "New", Patch( <SP List>, LookUp( <SP List>, ID = varPatchedID ), {dg: varNewDG } );
Met deze integer waarde in kolom ‘dg’ hebben we een eenvoudige manier om de data te verzamelen.
- We zoeken de grootste ‘dg’ en bouwen een lus van 1 tot dat getal.
- We halen alle records op waarvan de ‘dg’-waarde = de luswaarde (‘=’ kan worden gedelegeerd)
Conclusie
Ik heb de vermindering van het aantal patches alvast twee keer vernoemd, maar ik hoop dat de voordelen van deze aanpak intussen duidelijk zijn:
- Geen extra tool (Power Automate) om te onderhouden.
- Slechts een paar regels code.
- Geen typecasting nodig.
- Collections zijn hetzelfde als de SP lijst.
Nu heb je twee opties om uit te kiezen: Power Automate gebruiken en alle data in één keer opvragen, of de Power Apps-benadering gebruiken met een lus.
Veel plezier bij het verkennen! En als je ondersteuning nodig hebt: mijn collega’s en ik helpen je graag 😊.