09-21-2023 12:40 PM
SharePoint Batch Update, Create, & Upsert Template
(Also an option for full dataset synchronizations with the "Full Sync" template below)
Compared to the using the basic Apply to Each, Get items, & Update item approach on large amounts of data, this method requires a small fraction of the API calls towards the daily action limit and drastically reduces flow run-times.
It's currently set to take data from any Excel sheet and update records in SharePoint with corresponding data. It works with any potential Power Automate data-source, including HTTP API GET requests, but Excel provides a simple example.
Part of it works like a Vlookup function where it identifies if a row of updated data in Excel or another datasource matches another SharePoint key column and gets the SharePoint record ID for that match. Then it uses the batch update method to update those SharePoint records and it uses the batch create method to create new items for any records without a match.
David Wyatt's Flow Optimization Post For Loading SharePoint Records: https://www.linkedin.com/pulse/top-5-ways-optimize-your-flows-david-wyatt/?trackingId=X9bMmnTZ2QBuu4...
Microsoft Batch API Documentation: https://learn.microsoft.com/en-us/sharepoint/dev/sp-add-ins/make-batch-requests-with-the-rest-apis
TachyTelic.Net Blog & Videos
SharePoint Batch Create Flow
Blog: https://www.tachytelic.net/2021/06/power-automate-flow-batch-create-sharepoint-list-items/
Video: https://youtu.be/2dV7fI4GUYU
SharePoint Batch Delete Flow
Blog: https://www.tachytelic.net/2021/06/power-automate-delete-sharepoint-items/
Video: https://www.youtube.com/watch?v=2ImkuGpEeoo
Version 2.7 - Upsert
-Includes a batch create segment to create an upsert capability. If anyone wants to only update records, then they can remove the Batch Create section. If anyone wants to only create records, then they can go to the GenerateSPData action, remove the expression for the ID field and insert the null value expression.
-Further simplifies the set-up, removing the need to add any additional SharePoint Get items actions & removing the need for parallel branches.
-Can now work on lists with a few million items without adding more actions or branches. It also implements a faster load method using the SharePoint HTTP action as described in point 5 of this article.
-The batch loops have been changed from Do until loops to chunking into Apply to each loops so the batch actions can now run concurrently for additional speed. If you have many batches of data you want to process faster, you can try increasing the concurrency settings on the Apply to each loops containing the SendBatch actions.
-The "setting" inputs action was moved to the top of the flow to help accommodate the new streamlined set-up.
-A SP HTTP call now automatically fixes some issues with referencing the correct list name.
-Faster list load time.
-If you need to batch create &/or update hyperlink columns, check this post
-Adds another HTTP call to get the site users into an object indexed/reference-able by email addresses & gives an example of how to use that to batch update a person column. Anytime the updated source dataset has a blank or an email value not found in the top 5000 site users, it will replace any person in that item with a null value.
Updated set-up screenshots & instructions in this post: https://powerusers.microsoft.com/t5/Power-Automate-Cookbook/Batch-Update-SharePoint-List/m-p/2225500...
Full Sync V1.1 (Combined Upsert & Batch Deletion Sync)
The SharePoint Batch Full Sync template pulls in all the SP List & Source data to perform a batch upsert. But then it also adds on a Batch Deletion Sync to find & delete all the records in the SP List that are not in the Source dataset.
Now, this is initially set up to pull in all the datasource records for all batch actions in the same Do until Get source data loop. And that piece will be limited by the 100MB maximum message / variable size limits for Power Automate, so this Full Sync version will initially only work with datasources with a 100MB or less total size. But this is really only because I'm trying to keep the flow simpler for the majority of users who likely will not have datasources of many 100s of thousands of records.
If you want to further push out against this 100MB limitation, then you will need to separate out the source get data for the batch upsert section from another source get data for the batch deletion sync section. So for the batch upsert section you can use a set-up like in the main batch upsert template where it loads records with all columns 100,000 at a time (or 100 or 5000 or whatever your source dataset per load limitations are) and runs the batch upsert on each source load before running the Do until loop again to get the next source load (which avoids holding anywhere near 100MB in memory at once because it is performing things one load at a time). Then the batch deletion sync section can use a different source get data set-up similar to the "Do until Get destination list IDs + keys" section of the templates where each loop can pull a load from the source dataset & then use a Select action to select only a few of the columns to pass on to the variable holding everything in memory. Since deletions only require the primary key values, you can set the Select to only get the primary key column from each source data load & pass that onto the "Source data outputs" / variable. A full listing of all the primary key values in your source dataset will be much smaller than all columns for the entire table, so that 100MB limit should then hold a few million records worth of the required primary key data to run the batch deletion sync process.
Self Update (See the 1st comment below the main post for the zip download)
The SharePoint Self Batch Update assumes you just want to perform simple updates using only the existing data in the list and removes all the actions related to comparing two datasets to find updates. This may be much easier to use if you just want to quickly do something simple like get all the items created in the past month and mark them all with a Complete status.
But you will be limited to using just the data already in the list and any values you can manually input into the flow.
Version 1.5 - Update
This version makes it easier to handle cases where the list name may have changed since its creation and moves a few of the primary key column matching inputs to the 'settings' compose action so users don't have to look through & edit the more complicated expressions to set up the flow.
The flow can easily expand to any size of SharePoint list by adding more Get items actions and batch update parallel branches. If speed is a concern for anyone, there are ways to make the Get items actions all load in parallel too (up to 50 branches). It's really only limited by how much effort people want to put into their flows & lists.
Google Drive Link to Flow Zip Files: https://drive.google.com/file/d/10p7EB730xsEj-azVYuTIuu8dS0w-AflR/view?usp=sharing
Google Drive Link to Text File to a Scope Action Containing The Flow: https://drive.google.com/file/d/1BVGoeM5mykYlMobAyFkhuLRh3r7jMSLz/view?usp=sharing
Version 1 - Update
Version 1 Explanation Video: https://youtu.be/l0NuYtXdcrQ
Download The Template Batch Update Flow
Google Drive Link to Flow Zip Files: https://drive.google.com/file/d/10gFkycdx6zpRfrI-s_jCDwIK6dpyyDqk/view?usp=sharing
Google Drive Link to Text File to a Scope Action Containing The Flow: https://drive.google.com/file/d/1e6-INUykIT22ppVh5m4kxz8us_7qXy7q/view?usp=sharing
Formulas For Random Number Columns
SharePoint Rand1To50 Column Calculated Default Value Formula:
=INT(INT(RIGHT(NOW(),2))/2)
Excel Random Column Formula:
=ROUNDDOWN(((Rand()*100)+1)/2, 0)
If you have trouble importing any of the flows using the standard legacy import, you can also try importing a Power Apps Solutions package here: Re: Batch Update, Create, and Upsert SharePoint Li... - Page 25 - Power Platform Community (microsof...
Thanks for any feedback, & please subscribe to my YouTube channel (https://youtube.com/@tylerkolota?si=uEGKko1U8D29CJ86)
watch?v=QCkjQy6sHZg
Extrapolating where your questions were going, I redesigned the flow to only handle the larger file. Still the exact same issue 1055883 bytes read from stream, maximum 1048576 bytes allowed.
I redesigned the flow to handle the smaller one, 4048 rows. This test failed for the same reason, but different numbers 1063871 bytes read, versus 1048576 bytes maximum allowed.
Right now, I believe since the two read numbers are different, it's actually counting the characters in each field for every record, until it hits the maximum number of characters in bytes. The contents, tiny to very large, of the multi-line text field would drive the difference in the read numbers for the different files. The last record where it ended meant that field probably had a very large amount of text.
Can I fix this internal to the flow?
I broke the smaller file into two files with 2024 rows in each file. F#1 got the exact same 1062871 bytes read / 1048576 bytes allowed. So the break is within the first 2024 rows.
Dividing the file again, to see if it works. Same error same numbers. So, the maximum bytes size allowed is exceeded within the first 1012 rows.
Dividing the file again 506 records; got past the bytes issues, but now it failed @
This is weird, the condition to terminate the process was passed, but nothing above it failed.
Updating Hyperlink Columns
Looks like hyperlink columns take a JSON value in HTTP calls that looks like...
"ColumnName": {
"Description":"UrlTextToShow",
"Url":"Url"
}
So in the GenerateSPData action you will put the hyperlink column name on the left, then in the right side of the mapping you will put an expression like...
json(concat('{"Description":"', item()?['InsertSourceLinkColumnName'], '","Url":"', item()?['InsertSourceLinkColumnName'], '"}'))
I don't have any hyperlink columns, everything is either single line of text, number, or Multiple lines of text.
Here are the column names:
Source Excel File | Target SharePoint List | Data Type | Representational Value
ACTION_TAKEN | Title | Single line of text | CREATED
COURSE | Title1 | Single line of text | FML_2842_LP_3 (Primary Key field used by source agency)
NOTACTIVE | NOTACTIVE | Single line of text | N
CPNT_TITLE | CPNT_TITLE | Single line of text | Leading with Empathy - LP : Leveraging Diversity :
Del_MTH_ID | DEL_MTH_ID | Single line of text | Classroom
SUBJ_AREA_1 | SUBJ_AREA_1 | LP
CPNT_DESC | CPNT_DESC | Multiple Lines of Text | [Example provided previously in my posts]
CPNT_LEN | CPNT_LEN | Number | 8
CREDIT_HRS | CREDIT_HRS | Number | 8
SHOW_IN_CATALOG | SHOW_IN_CATALOG | Single line of text | Y
CATALOG_1 | CATALOG_1 | Single line of text | FM CERT 1
CATALOG_2 | CATALOG_2 | Single line of text | FM CERT 2 0r "" (Null)
CATALOG_3 | CATALOG_3 | Single line of text | FM CERT_3 0r "" (Null)
CPNT_TYPE | CPNT_TYPE | Single line of text | COURSE
SELF_RECORD_LRNGEVT | SELF_RECORD_LRNGEVT | Single line of text | Y
COL_NUMS_VAL!##! | COL_NUMS_VAL!##! | Single line of text | Y!##! {End of Original File Received, the below fields are created locally}
Column1 | Cloumn1 | Single line of text | Y or "" (Null)
LEVEL_1 | LEVEL_1 | Single line of text | FM CERT L1
LEVEL_2 | LEVEL_2 | Single line of text | FM CERT L2
LEVEL_3 | LEVEL_3 | Single line of text | FM CERT L3
Validation | Validation | Single line of text | TRUE
FM_myLearn | FM myLearn | Single line of text | N
As you can see most columns are very small, the only column that is very large, most times, is the CPNT_DESC which can contain more characters than all other columns combined, by a lot within a record.
There are No Hyperlink columns. I highly doubt adding your suggestion will help solve my problem.
The problem is now it fails at "Condition If SendBacth errors fail flow" Which is = True, then the "Terminate" command was followed. However, Nothing and I mean Nothing above that failed within the flow, everything has a green checkmark.
I one of my previous posts, you can see the Batch Upset task broken out as well. There are no Red Checkmarks.
In Batch Upsert how does the SendBatch errors fail the flow, when nothing above it fails? How do I fix this? It makes no sense, the flow did not fail any of the previous steps, but was set to "True" anyway, causing the flow to fail altogether, when maybe it shouldn't have?
The hyperlink information was from another user who started asking about it on LinkedIn. I added the post so I could link to it in the main post for anyone with similar questions.
For your scenario, you need to reduce the batch size to something where your dataset won’t ever exceed the maximum character limit. Maybe try something pretty low like 200.
The flow is explicitly set to fail with a terminate action whenever there is an error in a Send Batch http action for any individual row. It is set this way because that Send Batch always returns a success indicator as long as the message went through, even if most things failed to update or create for the list. This could be triggered by a single row failing to create or update & you can find more info by checking the Append to variable action inside the main update & create loops. Whichever loop run has some text in that action is where the Send Batch http had an error.
@Robert94
To update the lookup Id in a batch call should require the same set-up as the person column, but in the set of actions to create the equivalent of the Users reference Object for the Lookup table instead of using
/_api/web/siteusers?top=5000
in the SP HTTP action, you would use
/_api/Web/Lists/getByTitle('InsertLookupListName')/Items?$top=5000&$orderby=ID desc
assuming the relevant items for the lookup list will be in the most recent 5000 items added to it.
Then you would use the same actions as the person users list set-up to create the referenceable JSON object & then use similar logic in the later GenerateSPData action as the AssignedId example to reference the correct lookup column Id you want to change the lookup column value(s) to.
I didn't add such an example to the default template because it is a more complicated piece that most would have to remove from the template when they aren't looking to work with a lookup list.
This is how to update a Lookup column using the batch actions:
If the name of the column is Lookup, in the Select action as the name of the column you would write LookupId and as value the id of the Lookup:
{"LookupId": 120}
I've applied this Flow to an Excel file that has 85,926 rows. On the first run, the SharePoint list only had 84,790 items. I didn't see any failed steps that might indicate why some rows were not created as SP list items. When I compared the two data sources, it appeared that the missing items were in blocks of contiguous rows in the Excel file. When I ran the Flow a second time, it created some (but not all of the missing items). Any idea what might be happening here? It seems like the flow just "hiccups" and fails to create new items when it should.
i`m getting this error in a flow, and in another it works fine, the one I`m getting an error is a child flow, is there something i can do:
InvalidTemplate. Unable to process template language expressions in action 'SendBatch' inputs at line '0' and column '0': 'The template language expression 'json(decodeBase64(triggerOutputs().headers['X-MS-APIM-Tokens']))['$connections']['shared_sharepointonline_1']['connectionId']' cannot be evaluated because property 'X-MS-APIM-Tokens' doesn't exist, available properties are 'Accept-Language, User-Agent, x-ms-workflow-id, x-ms-workflow-version, x-ms-workflow-name, x-ms-workflow-system-id, x-ms-workflow-run-id, x-ms-workflow-run-tracking-id, x-ms-workflow-operation-name, x-ms-workflow-repeatitem-scope-name, x-ms-workflow-repeatitem-index, x-ms-workflow-repeatitem-batch-index, x-ms-execution-location, x-ms-workflow-subscription-id, x-ms-workflow-resourcegroup-name, x-ms-tracking-id, x-ms-correlation-id, x-ms-client-request-id, x-ms-client-tracking-id, x-ms-action-tracking-id, x-ms-activity-vector, Content-Type, Content-Length'. Please see https://aka.ms/logicexpressions for usage details.'.