I searched the internet and I can't find a response to this nor the documentation for it.
I need to dynamically generate Google forms questions with data from a Google spreadsheet using app script, but I don't know how to reference and read a spreadsheet.
In your spreadsheet select Tools > Script Editor and adapt this to your needs:
/**
After any change in the sheet, update the combobox options in the Form
*/
function onChange(e) {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0];
var range = sheet.getDataRange();
var values = range.getValues();
var comboValues = []; // <-- cheddar will go here
// in this example we are interested in column 0 and discarding row 1 (the titles)
for (var i = 1; i <= values.length; i++) {
var v = values[i] && values[i][0];
v && comboValues.push(v)
}
// Sort the values alphabetically, case-insensitive
comboValues.sort(
function(a, b) {
if (a.toLowerCase() < b.toLowerCase()) return -1;
if (a.toLowerCase() > b.toLowerCase()) return 1;
return 0;
}
);
Logger.log(comboValues);
// Use your form ID here. You can get it from the URL
var form = FormApp.openById('<my-form-id>');
/*
Uncomment this to display the item IDs
and pick the one that you want to modify
var items = form.getItems();
for (i = 0; i < items.length; i++) {
Logger.log("ID: " + items[i].getId(), ': ' + items[i].getType());
}
*/
form.getItemById(807137578).asListItem().setChoiceValues(comboValues);
};
To debug, select the script in the combobox and click either "play" or "debug". The first time you will have to give it permissions to interact with your spreadsheet and form.
Once you are satisfied with the result, in the editor select Resources > Triggers for the active project and add this method to be triggered with any modification on the spreadsheet (on change, not on edit).
After this, your form options will be changed in real time after any change in your spreadsheet.
It's pretty straightforward, see here: https://developers.google.com/apps-script/guides/sheets#reading
You just need to open the sheet by its doc key, select the data and read the cells as a JS object.
Here is an example which works for me, pls kindly check:
function getSpreadsheetData(sheetId) {
// This function gives you an array of objects modeling a worksheet's tabular data, where the first items — column headers — become the property names.
var arrayOfArrays = SpreadsheetApp.openById(sheetId).getDataRange().getValues();
var headers = arrayOfArrays.shift();
return arrayOfArrays.map(function (row) {
return row.reduce(function (memo, value, index) {
if (value) {
memo[headers[index]] = value;
}
return memo;
}, {});
});
}
function makeOurForm() {
var sheetId='input_your_sheet_id'
getSpreadsheetData(sheetId).forEach(function (row) {
// Set your form template as follows
var formName=row.Name
// Create your form programmatically, each row means one form
var form = FormApp.create(formName)
form.setDescription('xxx');
var capitalizedName = row.Name.charAt(0).toUpperCase() + row.Name.slice(1);
form.addSectionHeaderItem().setTitle(capitalizedName);
var item = form.addMultipleChoiceItem();
item.setTitle('xxx')
.setChoices([
item.createChoice('xxx'),
]);
form.addParagraphTextItem().setTitle('xxx');
});
}
You can get your sheet Id from url, for example:
https://docs.google.com/spreadsheets/d/YourSheetId/edit#gid=0
Let me know if you have any further questions.
Related
I have around 300 Spreadsheets that I need to copy all data from each spreadsheet and merge into a Master Spreadsheet. I have a spreadsheet that lists all 300 spreadsheet Ids. This script works however its Very slow!
I also tried to manually enter all document Ids as a variable and it did not seem to make a difference.
Is there a better way to handle?
function combineData() {
const masterID = "ID";
const masterSheet = SpreadsheetApp.openById(masterID).getSheets()[0];
let targetSheets = docIds();
for (let i = 0, len = targetSheets.length; i < len; i++) {
let sSheet = SpreadsheetApp.openById(targetSheets[i]).getActiveSheet();
let sData = sSheet.getDataRange().getValues();
sData.shift() //Remove header row
if (sData.length > 0) { //Needed to add to remove errors on Spreadsheets with no data
let fRow = masterSheet.getRange("A" + (masterSheet.getLastRow())).getRow() + 1;
let filter = sData.filter(function (row) {
return row.some(function (cell) {
return cell !== ""; //If sheets have blank rows in between doesnt grab
})
})
masterSheet.getRange(fRow, 1, filter.length, filter[0].length).setValues(filter)
}
}
}
function docIds() {
let listOfId = SpreadsheetApp.openById('ID').getSheets()[0]; //list of 300 Spreadsheet IDs
let values = listOfID.getDataRange().getValues()
let arrayId = []
for (let i = 1, len = values.length; i < len; i++) {
let data = values[i];
let ssID = data[1];
arrayId.push(ssID)
}
return arrayId
}
I believe your goal is as follows.
You have 300 Spreadsheets.
You want to retrieve the values from the 1st tab of all Spreadsheets and also, you want to put the retrieved values to the 1st tab of the master Spreadsheet.
You want to reduce the process cost of the script.
Issue and workaround:
In the current stage, unfortunately, there is no method for retrieving the values from multiple Spreadsheets, simultaneously. If the sample script is prepared, it is required to obtain the values from each spreadsheet in a loop. In this case, the process cost becomes high. I think that this might be the reason for your current issue.
In this answer, as another approach, I would like to propose the following flow.
Create the URL list for exporting the values from Spreadsheets.
In the current stage, when Sheets API is used in a loop, an error occurs. So, in this workaround, I use the URL for exporting Spreadsheet as CSV data. In this case, it seems that even when this URL is accessed with a loop, no error occurs.
Retrieve CSV values from the URLs using UrlFetchApp.fetchAll.
fetchAll method works with the asynchronous process. Ref (Author: me)
Merge the retrieved values by parsing CSV data as an array.
Put the values to the master Spreadsheet using Sheets API.
By this flow, I thought that the process cost can be reduced. When this flow is reflected in a sample script, how about the following sample script?
Sample script:
Please set masterID and ssId. And, please enable Sheets API at Advanced Google services. And, please run myFunction.
function myFunction() {
const masterID = "###"; // Please set the master Spreadsheet ID.
const ssId = "###"; // Please set the Spreadsheet ID including the Spreadsheet IDs you want to retrieve in column "B".
// Retrieve Spreadsheet IDs.
const sheet = SpreadsheetApp.openById(ssId).getSheets()[0];
const ssIds = sheet.getRange("B2:B" + sheet.getLastRow()).getDisplayValues().reduce((ar, [b]) => {
if (b) ar.push(b);
return ar;
}, []);
// Retrieve values from all Spreadsheets.
const workers = 50; // Please adjust this value.
const headers = { authorization: "Bearer " + ScriptApp.getOAuthToken() };
const reqs = [...Array(Math.ceil(ssIds.length / workers))].map(_ => ssIds.splice(0, workers).map(id => ({ url: `https://docs.google.com/spreadsheets/export?exportFormat=csv&id=${id}`, headers, muteHttpExceptions: true })));
const values = reqs.flatMap(r =>
UrlFetchApp.fetchAll(r).flatMap(rr => {
if (rr.getResponseCode() == 200) {
const [, ...val] = Utilities.parseCsv(rr.getContentText());
return val;
}
return [];
})
);
// Put values to the master sheet.
const masterSheet = SpreadsheetApp.openById(masterID).getSheets()[0];
Sheets.Spreadsheets.Values.update({ values }, masterID, `'${masterSheet.getSheetName()}'!A${masterSheet.getLastRow() + 1}`, { valueInputOption: "USER_ENTERED" });
// DriveApp.getFiles(); // This comment line is used for automatically detecting the scope for Drive API. So, please don't remove this line.
}
When this script is run,
Spreadsheet IDs are retrieved from column "B" of the 1st sheet in the Spreadsheet of ssId.
Values are retrieved from all Spreadsheets.
In this script, the values are retrieved from every 50 Spreadsheets with the asynchronous process. If you increase const workers = 50; to const workers = 100;, the values are retrieved from every 100 Spreadsheets. But, if an error occurs when this value is increased, please adjust the value.
Put values using Sheets API.
When I tested this script for 50 Spreadsheet, the processing time was about 20 seconds. But, I'm not sure about your actual situation. So, please test this script.
Note:
In your script, listOfID is not declared. Please be careful about this.
Unfortunately, I cannot know your all Spreadsheets. So, if all values are more than 10,000,000 cells, an error occurs because of the maximum number of cells in a Spreadsheet. Please be careful about this.
If the number of values is large, an error might occur. At that time, please check my report.
References:
fetchAll(requests)
Method: spreadsheets.values.update
The .setValues() and .getValues() function themselves already run quite heavily specially if you have large data in the sheet, and using it together with for loop will really cause it to be slow since it iterates over 1 by 1. How about changing the for loop to forEach()
Try:
function combineData() {
const masterID = "1aRQ7rW9tGF25xdmjAfOtT6HtyZKQq0_AIYOGSZMKOcA";
const masterSheet = SpreadsheetApp.openById(masterID).getSheetByName("Master");
let targetSheets = docIds();
targetSheets.forEach(function(x){
let sSheet = SpreadsheetApp.openById(x).getActiveSheet();
let sData = sSheet.getDataRange().getValues();
sData.shift() //Remove header row
if (sData.length > 0) { //Needed to add to remove errors on Spreadsheets with no data
let fRow = masterSheet.getRange("A" + (masterSheet.getLastRow())).getRow() + 1;
let filter = sData.filter(function (row) {
return row.some(function (cell) {
return cell !== ""; //If sheets have blank rows in between doesnt grab
})
})
masterSheet.getRange(fRow, 1, filter.length, filter[0].length).setValues(filter)
}
})
}
function docIds() {
let listOfId = SpreadsheetApp.openById('1aRQ7rW9tGF25xdmjAfOtT6HtyZKQq0_AIYOGSZMKOcA').getSheets()[0]; //list of 300 Spreadsheet IDs
let values = listOfId.getDataRange().getValues();
values.shift()
let arrayId = []
values.forEach(function(val){
let data = val;
let ssID = data[1];
arrayId.push(ssID)
})
return arrayId
}
Also here are some of the best practices to improve the performance of the script: Best Practices
More details on forEach:
forEach()
Let me know if this helps!
Use the Sheets API, depending on the data it is an order of magintude faster than the native SpreadsheetApp. Add the Google Sheets API under Services in the left pane of the Apps Script editor.
Here is a code snipped of how we use one or the other API:
if(gridData && gridHeight) {
let range = sheet.getRange(startRow, 1, gridHeight, gridData[0].length);
if(useSheetsAPI) {
try {
SpreadsheetApp.flush();
let valueRange = Sheets.newValueRange();
valueRange.values = gridData;
let idAndName = getSpreadsheetIdAndSheetNameByName_(sheetName);
let rangeA1 = idAndName.sheetName + '!' + range.getA1Notation();
let options = { valueInputOption: 'USER_ENTERED' };
let result = Sheets.Spreadsheets.Values.update(valueRange, idAndName.spreadsheetId, rangeA1, options);
debugLog_('sheetReplace(): Sheets.Spreadsheets.Values.update result: '+result);
} catch (err) {
Logger.log('sheetReplace() ERROR: %s', err.message);
return 'ERROR: sheetReplace() failed: ' + err.message;
}
} else {
range.setValues(gridData);
}
}
/**
* Get spreadsheet Id and sheet name by sheet name
*
* #param {string|null} name name of sheet, either "sheet_id:Tab Name", "Tab Name"
* #return {object} object object with spreadsheetId and sheetName
*/
function getSpreadsheetIdAndSheetNameByName_(name) {
let spreadsheetId = '';
if(name && name.length > 44 && name.indexOf(':') > 40) {
// assume format: "sheet_id:Tab Name"
spreadsheetId = name.replace(/:.*$/, '');
name = name.replace(/^.*?:/, '');
} else {
// assume format "Tab Name"
spreadsheetId = SpreadsheetApp.getActiveSpreadsheet().getId();
}
return { spreadsheetId: spreadsheetId, sheetName: name };
}
Also, I submitted an enhancement request for better performance, see https://issuetracker.google.com/issues/222337394 and vote for it.
I'm trying to use app script to give access to my Google sheet by searching through a webpage. so I don't have to give all the data. the search is based on a specific column and the result can be repeatable on the column itself but the other columns of the same row like price and item are different.
with my current code if the searched column has only characters the code works perfectly but once I add numbers to the targeted column on my google sheet the code stop working .. can you help me with that .. my knowledge is basic with coding
function doGet(e) {
return HtmlService.createTemplateFromFile("Index").evaluate()
.setTitle("WebApp: Search By Password")
.addMetaTag('viewport', 'width=device-width, initial-scale=1')
.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}
/* PROCESS FORM */
function processForm(formObject){
var concat = formObject.searchtext;
var result = "";
if(concat){//Execute if form passes search text
result = search(concat);
}
return result;
}
function search(searchtext = 'searchtext') {
let ar = [];
var spreadsheetId = '1aN8VLL4iKhGjmM84qhncG9cQfKigCWscMT-UkdzNhQs';
const names = ['Data', 'Data2'];
names.forEach((name) => {
var range = SpreadsheetApp.getActive().getSheetByName(name).getDataRange();
var data = range.getValues();
data.forEach(function (f) {
if (f[0] === searchtext) {
ar.push([f[0],f[1],f[2],f[3],f[4],f[5],f[6],f[7],f[8],f[9]]);
}
});
});
return ar;
};
thanks a lot
Try this f[0] == searchtext because === says the same object type and the same value. It may be preventing searchtext to being coerced into a number.
This is my first Google Script and I'm struggling a little bit while trying to bring back the values from a specific cell & sheet to another sheet.
I have a total of 18 columns, being the first one the ID which is going to be the input that the user would need to add in order to retrieve the data from one sheet to another. As the first one is the ID, and will be already be inputted by the user, I would need to retrieve the data from columns 2 to 18
Here is my code:
function SearchID() {
var columnIndex = 0;
var ss = SpreadsheetApp.getActiveSpreadsheet();
var formS = ss.getSheetByName("Manual Costs App"); // App sheet
var str = formS.getRange("D6").getValue(); // The ID to search will be inputted here
var dataS = ss.getSheetByName("Inputs").getDataRange().getValues(); // Retrieving the data based on the user input
for (var i = 0; i<=dataS.length; i++) {
var row = dataS[i];
if (row[columnIndex] == str) {
formS.getRange("D9").setValue(row[1]);
formS.getRange("D13").setValue(row[2]);
formS.getRange("D14").setValue(row[3]);
formS.getRange("D15").setValue(row[4]);
formS.getRange("D16").setValue(row[5]);
formS.getRange("D18").setValue(row[6]);
formS.getRange("D19").setValue(row[7]);
formS.getRange("D20").setValue(row[8]);
formS.getRange("D21").setValue(row[9]);
formS.getRange("D22").setValue(row[10]);
formS.getRange("D23").setValue(row[11]);
formS.getRange("D25").setValue(row[12]);
formS.getRange("D26").setValue(row[13]);
formS.getRange("D27").setValue(row[14]);
formS.getRange("D28").setValue(row[15]);
formS.getRange("D29").setValue(row[16]);
formS.getRange("D30").setValue(row[17]);
break;
}
}
}
The link to a sample spreadsheet of what I'm building is here
Update: Everything is fixed now! What I did was removing the space in the for loop. After that, it retrieved the data but a TypeError: Cannot read property '0'. Also solved it adding a break after the loop to avoid it.
It's a type in your for loop, notice how spelled length:
for (var i = 1; i <= values.lenght; i++)
You also don't want to set values line by line like you do, get a longer range and set the values with setValues() rather than setValue(). There's quite a bit of refactoring to do there actually.
The user did found the answer and updated it on the question.
Posting here as community wiki so it can be seen more clearly.
User's answer:
Update: Everything is fixed now! What I did was removing the space in the for loop. After that, it retrieved the data but a TypeError: Cannot read property '0'. Also solved it adding a break after the loop to avoid it.
function SearchID() {
var columnIndex = 0;
var ss = SpreadsheetApp.getActiveSpreadsheet();
var formS = ss.getSheetByName("Manual Costs App"); // App sheet
var str = formS.getRange("D6").getValue(); // The ID to search will be inputted here
var dataS = ss.getSheetByName("Inputs").getDataRange().getValues(); // Retrieving the data based on the user input
for (var i = 0; i<=dataS.length; i++) {
var row = dataS[i];
if (row[columnIndex] == str) {
formS.getRange("D9").setValue(row[1]);
formS.getRange("D13").setValue(row[2]);
formS.getRange("D14").setValue(row[3]);
formS.getRange("D15").setValue(row[4]);
formS.getRange("D16").setValue(row[5]);
formS.getRange("D18").setValue(row[6]);
formS.getRange("D19").setValue(row[7]);
formS.getRange("D20").setValue(row[8]);
formS.getRange("D21").setValue(row[9]);
formS.getRange("D22").setValue(row[10]);
formS.getRange("D23").setValue(row[11]);
formS.getRange("D25").setValue(row[12]);
formS.getRange("D26").setValue(row[13]);
formS.getRange("D27").setValue(row[14]);
formS.getRange("D28").setValue(row[15]);
formS.getRange("D29").setValue(row[16]);
formS.getRange("D30").setValue(row[17]);
break;
}
}
}
I'm creating a function in Google Apps Script. The purpose of this function is selecting the table from the document and move values to the created Spreadsheet. The problem is that I can't get the table from the document (debugging is OK, but logs show selected table as empty {}).
function addAnswersTable() {
var File = function(Path) { // File object constructor
this.Path = Path;
this.Doc = DocumentApp.openById(this.Path);
this.getTable = new function()
// This function defines
// a getTable method to get
// the first table in the Document
{
if (this.Doc != undefined) {
var range = this.Doc.getBody();
var tables = range.getTables();
var table = tables[0];
return table;
}
}
}
// Creating Excel Table, where first column
// of selected table should be moved
var Table = SpreadsheetApp.create("AnswersTable");
// Creating new File object
var TrueAnswersFile = new File
('1_ne9iBaK-Z36yUYrISr3gru3zw3Qdsneiu14sWnjn34');
// Calling getTable method to get the table placed in File
var TrueAnswersTable = TrueAnswersFile.getTable;
for (var i = 1; i <= TrueAnswersTable.getNumRows; i++) {
// Filling spreadsheet "A" column with cells'
// values from table stored in File
Table.getActiveSheet().getRange("A" + i).setValue(TrueAnswersTable.getCell(1, i).getValue());
};
}
I except the output in Spreadsheet column "A" like :
A1. Just
A2. Cells'
A3. List item with
A4. Values From Table
Actually spreadsheet is empty
You want to retrieve the values from the column "A" of Google Document and put the values to the column "A" of the created Spreadsheet.
The table of index 0 in the Document has 4 rows and 1 column.
The values of each row is Just, Cells', List item with, Values From Table.
I could understand like above. If my understanding is correct, how about this modification?
Modification points:
In your script, the method is not used as the function. By this, the method is not run.
For example, TrueAnswersFile.getTable and TrueAnswersTable.getNumRows.
No method is used.
For example, getValue() of TrueAnswersTable.getCell(1, i).getValue().
new of this.getTable = new function() is not required.
In your script, getCell(1, i) of TrueAnswersTable.getCell(1, i) retrieves the values at from column "B" of the row 2.
If you want to retrieve the values from the row 1 of the column "A", please modify to getCell(i - 1, 0). But in this modification, the start of index is 0. So you can use getCell(i, 0).
When setValue() is used in the for loop, the process cost becomes high. In your case, you can use setValues() instead of it.
When above points are reflected to your script, it becomes as follows.
Modified script:
function addAnswersTable() {
var File = function(Path) {
this.Path = Path;
this.Doc = DocumentApp.openById(this.Path);
this.getTable = function() { // Modified
if (this.Doc != undefined) {
var range = this.Doc.getBody();
var tables = range.getTables();
var table = tables[0];
return table;
}
}
}
var Table = SpreadsheetApp.create("AnswersTable");
var TrueAnswersFile = new File('1_ne9iBaK-Z36yUYrISr3gru3zw3Qdsneiu14sWnjn34');
var TrueAnswersTable = TrueAnswersFile.getTable();
var values = []; // Added
for (var i = 0; i < TrueAnswersTable.getNumRows(); i++) { // Modified
values.push([TrueAnswersTable.getCell(i, 0).getText()]) // Modified
};
Table.getRange("A1:A" + values.length).setValues(values); // Added
}
References:
getCell(rowIndex, cellIndex)
getText()
Benchmark: Reading and Writing Spreadsheet using Google Apps Script
I am working on a kendo grid with remote data, and currently when updating my grid, I use the dataItem.set() method to manually sync the grid with the data. This works fine, but unfortunately the aggregates in the footer are not refreshed. They refresh only when calling dataSource.fetch(), which hangs up the application for about 10 seconds. The users however, would like more excel-like responsiveness where every change they make is immediately reflected in the total, but also persisted to the database. Is this possible using the kendo api? Or do I have to do this manually with jQuery?
Edit: doesn't look like there's a built-in way so I fixed manually w/ jQuery.
Edit 2: Here's the code I used, generalized a bit and taking out some application specific quirks.
Kendo Grid Configuration:
$(gridId).kendoGrid({
columns: [
{
field: fieldToUpdate,
editor: customEditor,
//add 'data-field' attribute to footer/group footer
footerAttributes: { 'data-field': fieldToUpdate },
groupFooterAttributes: { 'data-field': fieldToUpdate }
},
//other fields...
],
//other config...
});
Custom Editor:
function customEditor(data) {
//store original and new value
//append textbox
//call custom update passing td and data w/ original/new values
}
Find Affected Aggregate Cells:
//Gets all affected aggregate cells after an update
function getTotalsCells($container, updatedField) {
var groups = $('#grid').data('kendoGrid').dataSource.group(),
$totals = $('.k-footer-template>td[data-field="' + updatedField + '"]'),
$row = $container.parent('tr');
for (var i = 0; i < groups.length; i++) {
var $groupTotal = $row.nextAll('.k-group-footer')
.eq(i)
.find('[data-field="..."]');
$totals = $totals.add($groupTotal);
}
return $totals;
}
Update Totals
$.fn.updateTotal = function (delta) {
this.each(function () {
var $container = $(this);
var origTotal = parseFloat($container.text() || 0);
var total = origTotal + delta;
$container.text(total);
});
};
Custom Update:
function updateGrid($container, data) {
var difference, field;
//get difference and updatedField
var $totals = getTotalsCells($container);
$totals.updateTotal(difference);
}
I feel like there must be a better way to do this, but the aggregate model doesn't seem to update.
My solution was to define a function that manually calculates the results and call this from within the footer template. Whenever the grid is refreshed the footer is also updated.
Client Template: #: sumDebits() #
function sumDebits() {
var $grid = $('#GridId');
var kendo = $grid.data().kendoGrid;
var data = kendo.dataSource.data();
var total = 0;
for (var i = 0; i < data.length; i++) {
var debit = parseFloat(data[i].Form.debit);
if (debit == NaN) {
debit = 0;
}
total = total + debit;
}
return total;
}
I had almost similar problem. I had a KendoGrid which i needed to refresh the row only (update HTML and Data) and update the groupFooterTemplateand and the footerTemplate after a modal close (which it had the edit cells i needed to update to the grid). I had "#progress/kendo-ui": "^2019.2.626". I know that is uses set but in this version set updates everything.
Bellow is the Code where you update groupFooterTemplateand ,footerTemplate , Html(row) and also excel is updated withoute Total Refresh of the Grid.
let grid = $('#grid').getKendoGrid(); // Kendo Grid
let dataItem = grid.dataItem(tr); // tr: JQuery (selected Row)
let index= grid.items().index(grid.select()); // or the selected Row
dataItem = data.length > 0 && data.length === 1 ? data : dataItem; // data is the new item with the same properties as the item datasource of the Grid. You can update all properties like below or just set one property.
dataItem.dirty = true;
let rowItem = grid.dataSource.at(index);
for (let [key, value] of Object.entries(dataItem )) {
rowItem.set(key, value); //
}
var grid = $("#gridName").data('kendoGrid');
var aggregateSum = grid.dataSource._aggregateResult;
//below code give you current aggregate value.
var sum = aggregateSum.<your_aggregate_columnname_here>.sum;
//assuming my Grid Column name is 'Amount'
var sum = aggregateSum.Amount.sum;
To change the aggregate value without refreshing page or without fetching the datasource, follow below steps
// Set the current aggregate value to 0
aggregateSum.<your_aggregate_columnname_here>.sum = 0;
// i.e. aggregateSum.Amount.sum = 0;
// Loop trough Grid data row by row
var gridData = grid.dataSource.data();
for (var i = 0; i < gridData.length; i++) {
var dataRow = gridData[i];
// to set the aggregate sum value
aggregateSum.Amount.sum += value;
// to set the cell value for that particular row
dataRow.set(ColumnName, value);
}
Note : Make Sure Call the Set() function in the end after updating the aggregate sum. If you will call Set function before setting aggregate sum, you will not be able to see the last iteration changes, as the changes will only reflect after set() function will get executed