Forum Discussion
how to create a query that paginates?
Hello Imke,
thanks for your reply. That did the trick! And the Counter<=1 had to be changed to Counter<1... Thanks a lot!
let
Pagination = List.Skip(List.Generate( () => [Last_Key = "init", Counter=0], // Start Value
each [Last_Key] <> null, // Condition under which the next execution will happen
each [ Last_Key = try if [Counter]<1 then "" else [WebCall][Value][offset] otherwise null,// determine the LastKey for the next execution
WebCall = try if [Counter]<1 then Json.Document(Web.Contents("https://api.airtable.com/v0/<api>/Room%20Assessment?api_key=<apikey>&pageSize=2")) else Json.Document(Web.Contents("https://api.airtable.com/v0/<api>/Room%20Assessment?api_key=<apikey>pageSize=2&offset="&Last_Key&"")), // retrieve results per call
Counter = [Counter]+1// internal counter
],
each [WebCall]
),1),
#"In Tabelle konvertiert" = Table.FromList(Pagination, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
#"Erweiterte Column1" = Table.ExpandRecordColumn(#"In Tabelle konvertiert", "Column1", {"HasError", "Value"}, {"Column1.HasError", "Column1.Value"}),
#"Erweiterte Column1.Value" = Table.ExpandRecordColumn(#"Erweiterte Column1", "Column1.Value", {"records", "offset"}, {"Column1.Value.records", "Column1.Value.offset"}),
#"Erweiterte Column1.Value.records" = Table.ExpandListColumn(#"Erweiterte Column1.Value", "Column1.Value.records"),
#"Erweiterte Column1.Value.records1" = Table.ExpandRecordColumn(#"Erweiterte Column1.Value.records", "Column1.Value.records", {"id", "fields", "createdTime"}, {"Column1.Value.records.id", "Column1.Value.records.fields", "Column1.Value.records.createdTime"}),
#"Erweiterte Column1.Value.records.fields" = Table.ExpandRecordColumn(#"Erweiterte Column1.Value.records1", "Column1.Value.records.fields", {"Condition", "Priority", "Room"}, {"Column1.Value.records.fields.Condition", "Column1.Value.records.fields.Priority", "Column1.Value.records.fields.Room"})
in
#"Erweiterte Column1.Value.records.fields"
Hi All,
I just wanted to share some code I wrote to get data out of elastic search using its scan and scroll pagination.
So if you have lots of data in elastic search, you must grab it in batches, and this code does exactly that, perhaps it will be helpful to someone:
let
FnGetElasticData = (url as text) as list =>
let
// init params
size=10000, // the size of the "chunks" of data that will be returned on each batch
scroll = "1m", // the time in minutes elastic search should keep the "context" alive
// build url for first fetch
operator = if Text.Contains(url, "?") then "&" else "?",
initUrl = url & operator & "scroll=" & scroll & "&size=" & Text.From(size),
// get first batch of results
initSource = Json.Document(Web.Contents(initUrl, [IsRetry=true])),
totalResults = initSource[hits][total], // the total number of results to return
iterations = Number.IntegerDivide(totalResults, size), // the total number of iterations we need to do
// build url for scroll
scrollId = initSource[_scroll_id], // the scroll id with wich we will fetch the rest of the results
uriParts = Uri.Parts(url), // for getting the host and scheme of the url
scrollUrl = uriParts[Scheme] & "://" & uriParts[Host] & "/_search/scroll?scroll=" & scroll & "&scroll_id=" & scrollId,
// this will return a scrolled result from elastic search
FnGetScrolledPage = (url as text) as list =>
let
response = Json.Document(Web.Contents(url, [IsRetry=true])),
data = response[hits][hits]
in
data,
// now loop through all of the iterations and return the data
resultsList = List.Generate(()=>[i=0, res=initSource[hits][hits]], // Set inital data
each [i] <= iterations, // Keep going until all of the iterations have been done or there is no more data
each [i=[i] + 1, res = FnGetScrolledPage(scrollUrl)], // Get next batch of results
each [res])
in
resultsList
in
FnGetElasticDataBasically, it will create a function that you can call with the URL for your elasticsearch query and it will return all of the results using paging.
Please note that this code will not work in automatic refreshes using the Power BI Gateway because that expects static URLs, you can get over this pretty easily by changing the code above to include the hard-coded URLs and then scheduled refresh will work.
- Anonymous9 years agoNot applicable
Hi,
I have a similar issue where by I am trying to retreive from a web api but the pagination is only set to 100.
My data is Xml, but I have noticed that the above discussion is related to json, so not sure if this will affect how the code needs to be written for me.
I need to retreive around 300,000 records but the pagination only returns 100 records at a time.
Here is what the URL looks like:
How can I make it so PBI returns all the records, not just 100 at a time?
Thank you
Mike
- ImkeF9 years ago
Community Champion
Hi Mike,
if the URL for the next page looks like so:
everything you have to do is to create a table with one row per necessary call:
Table.FromColumns({{1..300000/100}})Add another column where you reference the first column as a parameter/variable to your web call:
Web.Page(Web.Contents("http://example.co.uk/example/feedback-details?from=2016-01-01%2009:00:00&to=2017-05-03%2009:30:00&page="&Text.From([Column1])))It doesn't matter in what format the result will be returned. Build a function that retrieves one of it and apply it as a next step to every (returned results in each) row.
- Anonymous9 years agoNot applicable
Hi ImkeF,
I'm getting an error message around
&Text.From([Column1]))
Expression.Error:There is an unknown identifier. Did you use the [field] shorthand for a _[field] outside of an 'each' expression?
Regards
Mike