
Requête OData / pagination
Étiquetté : boucle, formulaire, power apps
Requête OData / pagination
Posté par Xavier NOEL-BRIAND sur 16 février 2023 à 9h52Bonjour, nous utilisons des requêtes OData dans PowerQuery pour récupérer des données. Sur le flux API de notre éditeur, nous avons une nouvelle contrainte technique > la pagination qui limite le nombre d’enregistrement à 1000 par appel.
Quelqu’un a-t-il déjà eu ce cas à traiter ?
Comment l’implémenter dans un environnement PowerQuery ?
PostID=IT9iFywp9PBDbYs
Jeremy a répondu Il y a 1 année, 2 mois 1 Membre · 3 Réponses- 3 Réponses
Bonjour Xavier,
J’ai déjà eu cela avec des limitation à 500 enr par appel. J’ai dû créer des fonctions en M pour gérer cela.
Voici mes fonctions :
importTablenletn Source = (tableImport) =>n letn firstPageUrl = "https://<NomDuSite>/api/" & tableImport,nn output = @GenerateByPage(n (lastPage) =>n letn next = if lastPage <> null then Value.Metadata(lastPage)[Next] else null,n urlToUse = if (next <> null) then next else firstPageUrl,n current = if (lastPage <> null and next = null) then null else getJson(urlToUse),n dataset = if (current <> null) then getDataset(current) else null,n link = if (current <> null) then current[next_page_url] else nulln inn dataset meta [Next=link]n ),nn getDataset = (json) =>n letn ConvertirEnTable = Table.FromRecords({json}),n Developper = Table.ExpandListColumn(ConvertirEnTable, "data"),n GarderData = Table.SelectColumns(Developper,{"data"})n in GarderData,n n getJson = (url) =>n letn waitForResult = WaitFor(n (iteration) =>n letn Source = Web.Contents(url, [Headers=[Authorization="Bearer " & ApiToken], ManualStatusHandling = {500}, IsRetry = iteration > 0]),n contentType = Value.Metadata(Source)[Content.Type],n actualResult = if contentType = "application/json" then Json.Document(Source) else nulln in actualResult,n (iteration)=> #duration(0, 0, 0, Number.Power(2, iteration)),n 5n )n inn if waitForResult = nulln then error "Wait for gave up after too many retry"n else waitForResultn inn outputninn Source
A noter que le Token est dans un paramètre que j’ai appelé “ApiToken”.
Ensuite, j’ai une fonction qui permet de générer par page :
GenerateByPagenletn Source = (getNextPage as function) as table =>n letn listOfPages = List.Generate(n () => getNextPage(null), // get the first page of datan (lastPage) => lastPage <> null, // stop when the function returns nulln (lastPage) => getNextPage(lastPage) // pass the previous page to the next function calln ),n // concatenate the pages togethern tableOfPages = Table.FromList(listOfPages, Splitter.SplitByNothing(), {"Column1"}),n firstRow = tableOfPages{0}?n inn // if we didn't get back any pages of data, return an empty tablen // otherwise set the table type based on the columns of the first pagen if (firstRow = null) thenn Table.FromRows({})nt // check for empty first tablen else if (Table.IsEmpty(firstRow[Column1])) thenn firstRow[Column1]n elsen Value.ReplaceType(n Table.ExpandTableColumn(tableOfPages, "Column1", Table.ColumnNames(firstRow[Column1])),n Value.Type(firstRow[Column1])n )ninn Source
Enfin, parce qu’il y a une limite de nombre de transactions par minute, j’avais dû créer une fonction d’attente :
WaitFornletn Source = (producer as function, interval as function, optional count as number) as any =>n letn list = List.Generate(n () => {0, null},n (state) => state{0} <> null and (count = null or state{0} < count),n (state) => if state{1} <> null then {null, state{1}} else {1 + state{0}, Function.InvokeAfter(() => producer(state{0}), interval(state{0}))},n (state) => state{1})n inn List.Last(list)ninn Source
J’espère que cela pourra t’aider. Peut-être une idée d’article à faire dès que je pourrais car c’est une vraie problématique.
ATTENTION : j’ai eu des problèmes avec ce genre de code car la source devient dynamique et elle ne peut pas être utilisée dans Power BI Services. En effet l’actualisation automatique des sources dynamiques ne fonctionne pas.
CommentID=rPOfMdeNFioAZOK, PostID=IT9iFywp9PBDbYs
Merci pour ton retour Jérémy Laplaine 🙂
On a créé une fonction personnalisée dans PowerQuery getOdata avec le code suivant et ça fonctionne 🎉
letn Source = (url as text) => letn GetPage = (url) => letn Source = Json.Document(Web.Contents(url, [Headers=[#"Authorization"="Bearer " & getToken()]])),n NextList = Source[value],n Result = try @NextList & @GetPage(Source[#"@odata.nextLink"]) otherwise NextListn inn Result,n Pages = GetPage(url),n #"Converti en table" = Table.FromList(Pages, Splitter.SplitByNothing(), null, null, ExtraValues.Error)n inn #"Converti en table"ninn Source
CommentID=bGNGNm6U4U8zwNw, PostID=IT9iFywp9PBDbYs
Magnifique ! Attention, vérifie bien que l’actualisation fonctionne côté Power BI Service. Si jamais, il faut utiliser le RelativePath.
SubCommentID=gHnYMLQM72obhqz, CommentID=bGNGNm6U4U8zwNw, PostID=IT9iFywp9PBDbYs
Connectez-vous pour répondre.