Forum Discussion
SharePoint list query alternative or optimization
- 5 years ago
hjaf FYI that I finally made a video to describe this approach, and am adding it here for others that may find this post. It also gets the count of items and makes the right number of API calls.
Get SharePoint List Data with Power BI ... Fast - YouTube
Also, a reminder to mark one of these as the solution.
Regards,
Pat
mahoneypat Awesome!
yes, I most definately need to use pagination ๐ near 20k items in the lists ๐
Replace after the ? with the following
?$skipToken=Paged=TRUE%26p_ID=30&$top=5000", [Headers=[Accept="application/json"]]))
I would make a list with = {0, 5000, 10000, 15000, 20000} or something more dynamic for when the list gets bigger. Convert that to a table and add a custom column that concatenates the list value in place of the 30 in red text above. Then expand the table to get all your data.
Sharepoint Lists can be slow. This approach has saved much refresh time.
If this works for you, please mark it as solution. Kudos are appreciated too. Please let me know if not.
Regards,
Pat
- hjaf6 years agoAdvocate I
mahoneypat you are awesome!
I have tried replying and asking for guidance only to have my post marked as spam. But I eventually came up with a solution. Do you concur with this? Quote or correct it, then I'll mark mark your reply as a solution so that other people may get the whole picture ๐
The query i ended up at that seems to be working(replaced RED values):- Column1 values is created with: List.Generate(() => 0, each _ < 120000, each _ + 5000)
- SPItems: Json.Document(Web.Contents("https://TennantShortName.sharepoint.com/sites/SiteName/_api/web/lists(guid'ListGUID')/items?$skipToken=Paged=TRUE%26p_ID="&Text.From([Column1])&"&$top=5000", [Headers=[Accept="application/json"]])))
Complete commented query:let Source = List.Generate(() => 0, each _ < 120000, each _ + 5000), // Generate a list that increments 5000 up to max value 120 000 #"Converted to Table" = Table.FromList(Source, Splitter.SplitByNothing(), null, null, ExtraValues.Error), // Convert the list into a table #"Added Custom" = Table.AddColumn(#"Converted to Table", "SPItems", each Json.Document(Web.Contents("https://<TennantShortName>.sharepoint.com/sites/<SiteName>/_api/web/lists(guid'<ListGUID>')/items?$skipToken=Paged=TRUE%26p_ID="&Text.From([Column1])&"&$top=5000", [Headers=[Accept="application/json"]]))), //custom column that does the actual query to sharepoint //Note: replace <TennantShortName>, <SiteName> and <ListGUID> //Instead of using list guid, you can use list names with GetByTitle(): "https://<TennantShortName>.sharepoint.com/sites/<SiteName>/_api/Web/Lists/GetByTitle('<List Title>')/items?$skipToken=Paged=TRUE%26p_ID="&Text.From([Column1])&"&$top=5000" #"Expanded SPItems" = Table.ExpandRecordColumn(#"Added Custom", "SPItems", {"odata.metadata", "odata.nextLink", "value"}, {"odata.metadata", "odata.nextLink", "value"}), //expand the results #"Removed Duplicates1" = Table.Distinct(#"Expanded SPItems", {"odata.nextLink"}), // Remove the duplicated nextLink items to get unique items #"Expanded value" = Table.ExpandListColumn(#"Removed Duplicates1", "value"), // Expand the results from queries into new rows #"Expanded value1" = Table.ExpandRecordColumn(#"Expanded value", "value", {"Id", "Title"}), // Expand wanted columns in the sharepoint list #"Removed Columns" = Table.RemoveColumns(#"Expanded value1",{"Column1", "odata.metadata", "odata.nextLink"}), // Remove columns from the initial query. #"Changed Type" = Table.TransformColumnTypes(#"Removed Columns",{{"Id", Int64.Type}, {"Title", type text}}) // Type setting in #"Changed Type"- mahoneypat6 years agoMicrosoft Employee
That looks good to me. I'm glad it works for you. I'm curious, how much of an upgrade time improvement did you see?
I wanted to write a blog with this hoosierbi.com (my blog about making Power BI pro bono with non-profit benefits). Your question exactly on this subject. I ended up doing a query version and function of it which makes it easier to modify/use. The function could be used if there were multiple lists that had the same columns and one had a tenant table, site, list (tenant, of course, would not change within a company).
Here they are:
As a function -
Leave
Origin (tenant name, name, name, and so on) >
Leave
site : site name,
tenant - tenant's name,
list : list name,
getdata รก Json.Document(Web.Contents("https://" & tenant & ".sharepoint.com/sites/" & site & "/_api/web/lists/GetByTitle('" & list & "')/items?$top-5000", [Headers-[Accept"application/json"]]))
In
Getdata
In
Source
As a consultation
Leave
Source?Leave
"NameOfMySite" website,
tenant : "NameOfMyTenant",
list of names "NameOfMyList",
getdata รก Json.Document(Web.Contents("https://" & tenant & ".sharepoint.com/sites/" & site & "/_api/web/lists/GetByTitle('" & list & "')/items?$top-5000", [Headers-[Accept"application/json"]]))
In
Getdata
In
SourceIf this works for you, mark it as a solution. Praise is also appreciated. Please let me know if you don't.
Best regards
Pat
- hjaf6 years agoAdvocate I
I probably did a lot sub-optimal steps in the previously used standard method, so I went from literally 3-4 hours, down to less than 3 minutes! But even just getting the raw data with the traditional query method still took 1+ hour, I believe its due to a lot of choice-columns and lookups in the list.
It would be interesting to create a function that determines the maximum ID and automatically get all the items. I think there is some room for further optimizing, regarding the overlapping queries this method produces. because the first 5k items have IDs ranging from 5k to 80k means that the first 16-ish queries will basically return the same data, but anyways. going down from hours to mere minutes is a giant leap I am very satisfied with ๐ Thank you again mahoneypat!
PS Updates to previous query: I realized did not clear out all the duplicates, so I added an additional duplication removal on IDs. I also put tennantId, sitename and list into parameters which made it a bit easier to configure:)
- ElliotK4 years agoHelper I
I really like this method, it is super fast and super easy to configure. However, I have found that whilst using this method, it doesn't pick up all the fields. I have tried expanding all the rows and columns, selecting all values but if simple does not pick up the one field I need. I really don't want to use a v2 connector as it is slow and terrible.
Any help would be appreciated.
- CmdrKeene4 years agoHelper IV
I can try to poke around and see if I can find a solution. What type of field is missing?
I will mention that person fields did not come in in a format that was great for me, so in my power query I also pulled in the user information table and then used the user ID to relate to it.
- hjaf6 years agoAdvocate I
Ok, this is promising!
I successfully got the first 5000 item in a breeze, however, the way you suggest iterating / paging the query is somewhat unclear to me.
In my case, the lowest ID starts at 5495, item # 5000 has ID around 80k. The "density" of the id range varies because of creations and deletions over time, and that sharepoint doesn't immediately re-use ID's. I also noticed that sharepoint provides an odata.nextLink value for the next 5k items, maybe I can somehow create an iteration that continues until this property is not appearing. Right now this appears to happen at about 120 000 (even though the item list contains just around 20k items).I can probably use a list as you suggested and have the list stop at 200 000 in 5000 increments, but not exactly sure how to make a query that iterates around the this list. can you provide an example?
PS:
I had to add "/items?" in the uri so the current uri for web.contents() in my case is as follows, could you use these uris in your answer so that when I tag the post as a solution, other people would have a better understanding ๐
= Json.Document(Web.Contents("https://<TennantShortName>.sharepoint.com/sites/<SiteShortName>/_api/Web/Lists/GetByTitle('<List Title>')/items?%24skiptoken=Paged%3dTRUE%26p_ID%3d<StartAtId>&%24top=5000" , [Headers=[Accept="application/json"]]))
or using list guid the url looks like this :
https://<TennantShortName>.sharepoint.com/sites/<SiteShortName>/_api/web/lists(guid'<item list guid>')/items?%24skiptoken=Paged%3dTRUE%26p_ID%3d<StartAtId>&%24top=5000 - munchkin6663 years agoHelper II
mahoneypat you are a true hero! Thank you for the video and for the comment! Worked for me like a charm ๐
- mahoneypat3 years agoMicrosoft Employee
munchkin666 Please see this article I wrote on this topic.
Updated โ Get SharePoint List Data โฆ Fast โ Hoosier BI
Pat