|
1 | 1 | ---
|
2 | 2 | title: Write a large dataset
|
3 | 3 | description: Learn how to split a large dataset into smaller write operations in Office Scripts.
|
4 |
| -ms.date: 05/13/2021 |
| 4 | +ms.date: 02/24/2023 |
5 | 5 | ms.localizationpriority: medium
|
6 | 6 | ---
|
7 | 7 |
|
8 | 8 | # Write a large dataset
|
9 | 9 |
|
10 | 10 | The `Range.setValues()` API puts data in a range. This API has limitations depending on various factors, such as data size and network settings. This means that if you attempt to write a massive amount of information to a workbook as a single operation, you'll need to write the data in smaller batches in order to reliably update a [large range](../../testing/platform-limits.md).
|
11 | 11 |
|
| 12 | +The first part of the sample shows how to write a large dataset in Excel. The second part expands the example to be part of a Power Automate flow. This is necessary if your script takes longer to run than the [Power Automate action timeout](../../testing/platform-limits.md#power-automate). |
| 13 | + |
12 | 14 | For performance basics in Office Scripts, please read [Improve the performance of your Office Scripts](../../develop/web-client-performance.md).
|
13 | 15 |
|
14 |
| -## Sample code: Write a large dataset |
| 16 | +## Sample 1: Write a large dataset in batches |
15 | 17 |
|
16 | 18 | This script writes rows of a range in smaller parts. It selects 1000 cells to write at a time. Run the script on a blank worksheet to see the update batches in action. The console output gives further insight into what's happening.
|
17 | 19 |
|
@@ -141,6 +143,119 @@ function getRandomString(length: number): string {
|
141 | 143 | }
|
142 | 144 | ```
|
143 | 145 |
|
144 |
| -## Training video: Write a large dataset |
| 146 | +### Training video: Write a large dataset |
145 | 147 |
|
146 | 148 | [Watch Sudhi Ramamurthy walk through this sample on YouTube](https://youtu.be/BP9Kp0Ltj7U).
|
| 149 | + |
| 150 | +## Sample 2: Write data in batches from a Power Automate flow |
| 151 | + |
| 152 | +For this sample, you'll need to complete the following steps. |
| 153 | + |
| 154 | +1. Create a workbook in OneDrive named **SampleData.xlsx**. |
| 155 | +1. Create a second workbook in OneDrive named **TargetWorkbook.xlsx**. |
| 156 | +1. Open **SampleData.xlsx**. |
| 157 | +1. Add sample data. You can use the script from the [Write a large dataset in batches](#sample-1-write-a-large-dataset-in-batches) section to generate this data. |
| 158 | +1. Create and save both of the following scripts. |
| 159 | +1. Follow the steps under [Power Automate flow: Read and write data in a loop](#power-automate-flow-read-and-write-data-in-a-loop) to create the flow. |
| 160 | + |
| 161 | +### Sample code: Read part of a workbook |
| 162 | + |
| 163 | +```TypeScript |
| 164 | +function main(workbook: ExcelScript.Workbook, startRow: number, batchSize: number) : string[][] { |
| 165 | + // This sample only reads the first worksheet in the workbook. |
| 166 | + const sheet = workbook.getWorksheets()[0]; |
| 167 | + |
| 168 | + // Get the boundaries of the range. |
| 169 | + // Note that we're assuming usedRange is too big to read or write as a single range. |
| 170 | + const usedRange = sheet.getUsedRange(); |
| 171 | + const lastColumnIndex = usedRange.getLastColumn().getColumnIndex(); |
| 172 | + const lastRowindex = usedRange.getLastRow().getRowIndex(); |
| 173 | + |
| 174 | + // If we're starting past the last row, exit the script. |
| 175 | + if (startRow > lastRowindex) { |
| 176 | + return [[]]; |
| 177 | + } |
| 178 | + |
| 179 | + // Get the next batch or the rest of the rows, whichever is smaller. |
| 180 | + const rowCountToRead = Math.min(batchSize, (lastRowindex - startRow + 1)); |
| 181 | + const rangeToRead = sheet.getRangeByIndexes(startRow, 0, rowCountToRead, lastColumnIndex + 1); |
| 182 | + return rangeToRead.getValues() as string[][]; |
| 183 | +} |
| 184 | + |
| 185 | +``` |
| 186 | + |
| 187 | +### Sample code: Write part of a workbook |
| 188 | + |
| 189 | +```TypeScript |
| 190 | +function main(workbook: ExcelScript.Workbook, data: string[][], currentRow: number, batchSize: number): boolean { |
| 191 | + // Get the first worksheet. |
| 192 | + const sheet = workbook.getWorksheets()[0]; |
| 193 | + |
| 194 | + // Set the given data. |
| 195 | + if (data && data.length > 0) { |
| 196 | + sheet.getRangeByIndexes(currentRow, 0, data.length, data[0].length).setValues(data); |
| 197 | + } |
| 198 | + |
| 199 | + // If we wrote less data than the batch size, signal the end of the flow. |
| 200 | + return batchSize > data.length; |
| 201 | +} |
| 202 | +``` |
| 203 | + |
| 204 | +### Power Automate flow: Read and write data in a loop |
| 205 | + |
| 206 | +1. Sign into [Power Automate](https://flow.microsoft.com) and create a new **Instant cloud flow**. |
| 207 | +1. Choose **Manually trigger a flow** and select **Create**. |
| 208 | +1. Add a **New step** to track the current row being read and written. Make a new **Initialize variable** action with the following values. |
| 209 | + * **Name**: currentRow |
| 210 | + * **Type**: Integer |
| 211 | + * **Value**: 0 |
| 212 | + |
| 213 | + :::image type="content" source="../../images/write-large-dataset-1.png" alt-text="The completed 'Initialize variable' step for the 'currentRow'."::: |
| 214 | +1. Add a **New step** to set the number of rows to be read in a single batch. Depending on the number of columns, this may need to be smaller to avoid the data transfer limits. Make a new **Initialize variable** action with the following values. |
| 215 | + * **Name**: batchSize |
| 216 | + * **Type**: Integer |
| 217 | + * **Value**: 10000 |
| 218 | + |
| 219 | + :::image type="content" source="../../images/write-large-dataset-2.png" alt-text="The completed 'Initialize variable' step for the 'batchSize'."::: |
| 220 | +1. Add a **Do until** control. The flow will read chunks of the data until it has all been copied. You'll use the value of **-1** to indicate the end of the data has been reached. Give the control the following values. |
| 221 | + * **Choose a value**: *currentRow* (dynamic content) |
| 222 | + * **is equal to** (from the dropdown list) |
| 223 | + * **Choose a value**: -1 |
| 224 | + |
| 225 | + :::image type="content" source="../../images/write-large-dataset-3.png" alt-text="The completed 'Do until' control."::: |
| 226 | +1. The remaining steps are added inside the **Do until** control. Next, call the script to read the data. Add an **Excel Online (Business)** connector with the **Run script** action. Use the following values for the action. |
| 227 | + * **Location**: OneDrive for Business |
| 228 | + * **Document Library**: OneDrive |
| 229 | + * **File**: "SampleData.xlsx" (as selected by the file picker) |
| 230 | + * **Script**: Read selected rows |
| 231 | + * **startRow**: *currentRow* (dynamic content) |
| 232 | + * **batchSize**: *batchSize* (dynamic content) |
| 233 | + |
| 234 | + :::image type="content" source="../../images/write-large-dataset-4.png" alt-text="The completed 'Run script' action for the script that reads the data."::: |
| 235 | +1. Call the script to write the data. Add a second **Excel Online (Business)** connector with the **Run script** action. Use the following values for the action. |
| 236 | + * **Location**: OneDrive for Business |
| 237 | + * **Document Library**: OneDrive |
| 238 | + * **File**: "TargetWorkbook.xlsx" (as selected by the file picker) |
| 239 | + * **Script**: Write data at row location |
| 240 | + * **startRow**: *currentRow* (dynamic content) |
| 241 | + * **batchSize**: *batchSize* (dynamic content) |
| 242 | + |
| 243 | + :::image type="content" source="../../images/write-large-dataset-5.png" alt-text="The completed 'Run script' action for the script that writes the data."::: |
| 244 | +1. Update the current row to reflect that a batch of data has been read and written. Add an **Increment variable** action with the following values. |
| 245 | + * **Name**: currentRow |
| 246 | + * **Value**: *batchSize* (dynamic content) |
| 247 | + |
| 248 | + :::image type="content" source="../../images/write-large-dataset-6.png" alt-text="The completed 'Increment variable' step for the 'currentRow'."::: |
| 249 | +1. Add a **Condition** control to check if the scripts have read everything. The "Write data at row location" script returns true when it has written fewer rows than the batch size allows. This means it's at the end of the data set. Create the **Condition** control with the following values. |
| 250 | + * **Choose a value**: *result* (dynamic content from **Run script**) |
| 251 | + * **is equal to** (from the dropdown list) |
| 252 | + * **Choose a value**: *true* (expression) |
| 253 | + |
| 254 | + :::image type="content" source="../../images/write-large-dataset-7.png" alt-text="The completed 'Condition' control."::: |
| 255 | +1. Under the **If yes** section of the **Condition** control, set the **currentRow** variable to be **-1**. Create a **Set variable** action with the following values. |
| 256 | + * **Name**: currentRow |
| 257 | + * **Value**: -1 |
| 258 | + |
| 259 | + :::image type="content" source="../../images/write-large-dataset-8.png" alt-text="The 'If yes' path with the completed 'Set variable' control."::: |
| 260 | +1. Save the flow. Use the **Test** button on the flow editor page or run the flow through your **My flows** tab. Be sure to allow access when prompted. |
| 261 | +1. The "TargetWorkbook.xlsx" file should now have the data from "SampleData.xlsx". |
0 commit comments