Google App Script Exceeded Maximum Execution Limit - google-apps-script

I've been attempting to export the entire contents of my spreadsheet. The code works fine, but it displays an error message that says Maximum execution limit exceeded. According to my research, the maximum execution time is only 6 minutes. I'm new to this and am still trying to figure it out. Could you kindly help me in determining a possible solution for this?
Here's the code that I'm currently using...
function PrintMultiple() {
const srcSs = SpreadsheetApp.getActiveSpreadsheet();
const sheet = srcSs.getSheetByName("TEMPLATE");
const values = sheet.getRange("C2").getDataValidation().getCriteriaValues()[0].getValues().flat().filter(String);
const dstSs = SpreadsheetApp.create("tempSpreadsheet");
SpreadsheetApp.getActive().toast("About to take some action... Please wait...");
values.forEach(v => {
sheet.getRange("C2").setValue(v);
SpreadsheetApp.flush();
const tempSheet = sheet.copyTo(srcSs);
const range = tempSheet.getDataRange();
range.copyTo(range, {contentsOnly: true});
tempSheet.getRange("B2:2").clear().clearDataValidations();
tempSheet.getDrawings().forEach(e => e.remove());
tempSheet.deleteColumn(1);
tempSheet.deleteRow(1);
tempSheet.deleteRow(2);
tempSheet.deleteRow(3);
tempSheet.copyTo(dstSs);
srcSs.deleteSheet(tempSheet);
});
dstSs.deleteSheet(dstSs.getSheets()[0]);
}

I believe your goal is as follows.
You want to reduce the process cost of your script.
From your script, when the length of values is large, I thought that the process of copy might be the high cost. So, in this case, how about using Sheets API? I thought that when Sheets API is used, the process cost of your script might be able to be reduced. When Sheets API is used for your script, it becomes as follows.
Modified script:
Before you use this script, please enable Sheets API at Advanced Google services.
function PrintMultiple() {
const ss = SpreadsheetApp.getActiveSpreadsheet().copy("tempSpreadsheet");
const sheet = ss.getSheetByName("TEMPLATE");
const sourceSheetId = sheet.getSheetId();
sheet.getDrawings().forEach(e => e.remove());
const values = sheet.getRange("C2").getDataValidation().getCriteriaValues()[0].getValues().flat().filter(String);
const requests1 = values.flatMap((v, i) => {
const sheetId = 123456 + i;
return [
{ duplicateSheet: { newSheetName: `page${i + 1}`, sourceSheetId, newSheetId: sheetId, insertSheetIndex: i + 2 } },
{ updateCells: { range: { sheetId: sheetId, startRowIndex: 1, endRowIndex: 2, startColumnIndex: 2, endColumnIndex: 3 }, rows: [{ values: [{ userEnteredValue: { numberValue: v } }] }], fields: "userEnteredValue.numberValue" } },
];
});
Sheets.Spreadsheets.batchUpdate({ requests: requests1 }, ss.getId());
const requests2 = values.flatMap((_, i) => {
const sheetId = 123456 + i;
return [
{ copyPaste: { source: { sheetId }, destination: { sheetId }, pasteType: "PASTE_VALUES" } },
{ deleteDimension: { range: { sheetId, startIndex: 0, endIndex: 3, dimension: "ROWS" } } },
{ deleteDimension: { range: { sheetId, startIndex: 0, endIndex: 1, dimension: "COLUMNS" } } },
];
});
Sheets.Spreadsheets.batchUpdate({ requests: requests2 }, ss.getId());
ss.deleteSheet(sheet);
ss.deleteSheet(ss.getSheets()[0]);
}
In this modification, the method of batchUpdate of Sheets API is used for copying values and deleting rows and columns.
When this script is run, "tempSpreadsheet" Spreadsheet is created to the root folder.
Reference:
Method: spreadsheets.batchUpdate

Related

Having issue populating table in Sheets using GAS

I found a solution on StackOverflow that I have been using to populate table data from some websites and haven't had any issues with the script (including some modifications I would make depending on the site, etc...) But, I'm having trouble getting the data from this website to populate although I am seeing the response from the Logger.log(table)
Is this because table is not a valid JSON? Is there any way to modify the script to pull this data?
function senate() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
const url = 'html';
const sheetName = "senate";
var dstSheet = ss.getSheetByName("senate");
var lr = dstSheet.getLastRow();
const html = UrlFetchApp.fetch(url).getContentText();
const tables = [...html.matchAll(/<table[\s\S\w]+?<\/table>/g)];
Logger.log(tables)
if (tables !== null) {
const ss = SpreadsheetApp.getActiveSpreadsheet();
Sheets.Spreadsheets.batchUpdate({ requests: [{ pasteData: { html: true, data: tables, type: "PASTE_VALUES", coordinate: { sheetId: ss.getSheetByName(sheetName).getSheetId(),rowIndex: lr, columnIndex: 0 } } }] }, ss.getId());
return;
}
throw new Error("Expected table cannot be retrieved.");
}
If you are using this sample script, I think that in this case, tables is an array. So, how about the following modification?
From:
Sheets.Spreadsheets.batchUpdate({ requests: [{ pasteData: { html: true, data: tables, type: "PASTE_VALUES", coordinate: { sheetId: ss.getSheetByName(sheetName).getSheetId(),rowIndex: lr, columnIndex: 0 } } }] }, ss.getId());
To:
Sheets.Spreadsheets.batchUpdate({ requests: [{ pasteData: { html: true, data: tables[0][0], type: "PASTE_VALUES", coordinate: { sheetId: ss.getSheetByName(sheetName).getSheetId(),rowIndex: lr, columnIndex: 0 } } }] }, ss.getId());
When I saw tables.length, it's 1. So, in this modification, data: tables was modified to data: tables[0][0].

specific columns of selected row for print

How to set specific columns of selected row for print ? Google Apps Script - Google Sheets
Where I select a row of the google sheet, the data of these columns should be printed by the macro ("A", "B", "J", "S").
I've written this macro to select rows but I don't know how to make more changes required
function print() {
var spreadsheet = SpreadsheetApp.getActive();
var sheet = spreadsheet.getActiveSheet();
sheet.getRange(spreadsheet.getCurrentCell().getRow(), 1, 1, sheet.getMaxColumns()).activate();
}
I believe your goal is as follows.
When you select a cell, you want to retrieve the values of the specific columns of the row of the selected cell.
In this case, how about the following modification?
Modified script:
function print() {
var selectColumns = ["A", "B", "J", "S"]; // This is from your question.
var sheet = SpreadsheetApp.getActiveSheet();
var currentRow = sheet.getCurrentCell().getRow();
var columnIndex = selectColumns.map(letter => [...letter.toUpperCase()].reduce((c, e, i, a) => (c += (e.charCodeAt(0) - 64) * Math.pow(26, a.length - i - 1)), -1));
var values = sheet.getRange(currentRow, 1, 1, sheet.getMaxColumns()).getValues().map(r => columnIndex.map(c => r[c]))[0].join(",");
console.log(values) // Here, you can also confirm the values in the log.
Browser.msgBox(values); // You can see the values at a dialog of Spreadsheet.
}
When you select a cell and run this script, the values of the specific columns "A", "B", "J", "S" of the row of the selected cell are retrieved.
At columnIndex, the column letters are converted to the column indexes.
From sheet.getRange(spreadsheet.getCurrentCell().getRow(), 1, 1, sheet.getMaxColumns()).activate();, if you want to activate the specific columns, how about the following modification?
function print2() {
var selectColumns = ["A", "B", "J", "S"]; // This is from your question.
var sheet = SpreadsheetApp.getActiveSheet();
var currentRow = sheet.getCurrentCell().getRow();
sheet.getRangeList(selectColumns.map(e => e + currentRow)).activate();
}
Reference:
map()
Added 1:
From your following reply,
I mean when i using function print2() if selectColumns = ["A", "B", "C" ] , Cells A B C are highlighted And that's great. but when i try To Use CTRL + P and And I make the settings related to print the selected cells, I only see cell c in the print output
First, in this case, it is required to select the continuous ranges like "A1:C1". When the cells "A1:C1" and "E1" are selected, only "E1" is shown. And, when the cells are selected using RangeList, the cells are selected for every cell. I thought that this might be the reason for your current issue. So, when you want to use the selected cells using the printer setting, how about the following sample script?
Sample script:
When you use this script, please set startColumn and endColumn. And, please select a cell. And, please run the script. By this, in this sample, the columns "A" to "C" are selected. When you push CTRL + P and do the settings related to print the selected cells, you can see the 3 cells.
function print3() {
var startColumn = "A"; // Please set the start column.
var endColumn = "C"; // Please set the end column.
var sheet = SpreadsheetApp.getActiveSheet();
var currentRow = sheet.getCurrentCell().getRow();
sheet.getRange(`${startColumn}${currentRow}:${endColumn}${currentRow}`).activate();
}
Added 2:
If you want to use the discrete columns and cells, how about the following sample script?
Sample script:
This script uses Sheets API. So, please enable Sheets API at Advanced Google services.
When you use this script, please set selectColumns. In this case, you can set the discrete columns. And, please select a cell, and run the script of print4. By this, only the columns of selectColumns of the selected row are shown. By this, when you push CTRL + P, you can see the showing cells. This is another workaround for achieving your goal.
After your work is finished, when you run showAll, all rows and columns are shown.
function print4() {
var selectColumns = ["A", "B", "J", "S"]; // This is from your question.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var currentRow = sheet.getCurrentCell().getRow();
var columnIndex = selectColumns.map(letter => [...letter.toUpperCase()].reduce((c, e, i, a) => (c += (e.charCodeAt(0) - 64) * Math.pow(26, a.length - i - 1)), -1));
var sheetId = sheet.getSheetId();
var requests = [...Array(sheet.getMaxColumns())].reduce((ar, _, i) => {
if (!columnIndex.includes(i)) {
ar.push({ updateDimensionProperties: { range: { sheetId, startIndex: i, endIndex: i + 1, dimension: "COLUMNS" }, properties: { hiddenByUser: true }, fields: "hiddenByUser" } });
}
return ar;
}, []);
var maxRows = sheet.getMaxRows();
if (currentRow == 1) {
requests.push({ updateDimensionProperties: { range: { sheetId, startIndex: currentRow, endIndex: maxRows, dimension: "ROWS" }, properties: { hiddenByUser: true }, fields: "hiddenByUser" } });
} else if (currentRow == maxRows) {
requests.push({ updateDimensionProperties: { range: { sheetId, startIndex: 0, endIndex: maxRows - 1, dimension: "ROWS" }, properties: { hiddenByUser: true }, fields: "hiddenByUser" } });
} else {
requests.push({ updateDimensionProperties: { range: { sheetId, startIndex: 0, endIndex: currentRow - 1, dimension: "ROWS" }, properties: { hiddenByUser: true }, fields: "hiddenByUser" } });
requests.push({ updateDimensionProperties: { range: { sheetId, startIndex: currentRow, endIndex: maxRows, dimension: "ROWS" }, properties: { hiddenByUser: true }, fields: "hiddenByUser" } });
}
Sheets.Spreadsheets.batchUpdate({ requests }, ss.getId());
}
function showAll() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
const requests = [{ updateDimensionProperties: { range: { sheetId: sheet.getSheetId(), dimension: "COLUMNS" }, properties: { hiddenByUser: false }, fields: "hiddenByUser" } }, { updateDimensionProperties: { range: { sheetId: sheet.getSheetId(), dimension: "ROWS" }, properties: { hiddenByUser: false }, fields: "hiddenByUser" } }];
Sheets.Spreadsheets.batchUpdate({ requests }, ss.getId());
}

Moving rows google sheets

I am trying to transfer rows of data from Sheet 1 to Sheet 2.
Thank you
I believe your goal is as follows.
Your script works fine. But, you want to reduce the process cost of your script.
In this case, how about the following modification?
Modified script:
In this modification, the rows are copied using setValues and deleted by Sheets API. By this, I thought that the process cost might be able to be reduced a little. So, please enable Sheets API at Advanced Google services before you use this script.
function archive() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var firstSheet = ss.getSheetByName("Sheet 1");
var firstSheetValues = firstSheet.getRange(1, 1, firstSheet.getLastRow(), firstSheet.getLastColumn()).getValues();
var sheetId = firstSheet.getSheetId();
var {values, requests} = firstSheetValues.reduce(function (o, r, i) {
if (r[1] == "Archive") {
o.values.push(r);
o.requests.push({ deleteDimension: { range: { sheetId, startIndex: i, endIndex: i + 1, dimension: "ROWS" } } });
}
return o;
}, { values: [], requests: [] });
var secondSheet = ss.getSheetByName("Sheet 2");
secondSheet.getRange(secondSheet.getLastRow() + 1, 1, values.length, values[0].length).setValues(values);
Sheets.Spreadsheets.batchUpdate({requests: requests.reverse()}, ss.getId());
}
References:
Method: spreadsheets.batchUpdate
DeleteDimensionRequest

Group rows with appscript

I have a sheet with more than 3000 rows and I want to group those rows by a parameter in ColA. So all rows having '1' in colA should be grouped under the row above with '0' in colA. Once groups are created I want them to collapse.
Since the script will be triggered daily upon data update, I also need the before-created groups to be removed so the new ones can be properly created.
I have several scrips doing what I need but it takes forever for them to go through all the rows. Is it possible to optimize them in some way or perhaps a different approach can be used for my needs? Thanks in advance for your help!
function removeAllGroups1() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName("Pipeline");
const rg = sh.getDataRange();
const vs = rg.getValues();
vs.forEach((r, i) => {
let d = sh.getRowGroupDepth(i + 1);
if (d >= 1) {
sh.getRowGroup(i + 1, d).remove()
}
});
}
function groupRows1() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Pipeline');
const levels = sh.getRange(2, 1, sh.getLastRow() - 1).getValues().flat();
levels.forEach((e, i) => sh.getRange(i + 2, 1).shiftRowGroupDepth(e));
}
function collapse() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Pipeline');
let lastRow = sh.getDataRange().getLastRow();
for (let row = 1; row < lastRow; row++) {
let depth = sh.getRowGroupDepth(row);
if (depth < 1) continue;
sh.getRowGroup(row, depth).collapse();
}
}
Data Sample: https://docs.google.com/spreadsheets/d/10BNrnAyQw89gy-Sj3CLiz4AgVtFI0AjXTvc0REGGTfY/edit#gid=113574154
I believe your goal is as follows.
You want to group the rows with high process speed.
You want to delete all groups with high process speed.
You want to collapse all groups with high process speed.
From the above goal, I thought that when Sheets API is used, the process cost can be reduced. And, Sheets API can group rows, delete all groups and collapse all groups.
Sample script:
Before you run this script, please enable Sheets API at Advanced Google services.
function removeAllGroups2() {
const sheetName = "sample";
const ss = SpreadsheetApp.getActive();
const ssId = ss.getId();
const sheetId = ss.getSheetByName(sheetName).getSheetId();
const n = Sheets.Spreadsheets.get(ssId, { ranges: [sheetName] }).sheets[0].rowGroups.reduce((n, { depth }) => n < depth ? depth : n, 0);
const requests = Array(n).fill("").map(_ => ({ deleteDimensionGroup: { range: { sheetId, dimension: "ROWS" } } }));
Sheets.Spreadsheets.batchUpdate({ requests }, ssId);
}
function groupRows2() {
const sheetName = "sample";
const ss = SpreadsheetApp.getActive();
const sheet = ss.getSheetByName(sheetName);
const levels = sheet.getRange("A2:A" + sheet.getLastRow()).getValues();
const sheetId = sheet.getSheetId();
const requests = levels.flatMap(([a], i) => Array(a).fill("").map(_ => ({ addDimensionGroup: { range: { sheetId, startIndex: i + 1, endIndex: i + 2, dimension: "ROWS" } } })));
Sheets.Spreadsheets.batchUpdate({ requests }, ss.getId());
}
function collapse2() {
const ss = SpreadsheetApp.getActive();
const requests = Sheets.Spreadsheets.get(spreadsheetId, {ranges: ["sample"]}).sheets[0].rowGroups.map(r => {
r.collapsed = true;
return { updateDimensionGroup: { fields: "*", dimensionGroup: r }};
});
Sheets.Spreadsheets.batchUpdate({ requests }, ss.getId());
}
Note:
I tested these sample scripts using your sample Spreadsheet. So when the structure of the Spreadsheet is different from your sample Spreadsheet, these scripts might not be able to be used. Please be careful about this. At first, please test them using your sample script.
References:
Method: spreadsheets.get
Method: spreadsheets.batchUpdate
DeleteDimensionGroupRequest
AddDimensionGroupRequest
UpdateDimensionGroupRequest

How to append an html table to a sheet

This script sends the data content of an html table to a Google Sheet.
But I now need it to append the data to the next available row.
I've used appendRow() in many cases, but I'm not sure of the syntax in this particular case.
function pasteRequisicaoHtml(table) {
var ss = SpreadsheetApp.openById("1J_7GZ1C7pgHuRsdfsdfsdfsdf");
var sheet = ss.getSheetByName('Sheet5').getSheetId();
var req = {
requests: [
{
pasteData: {
html: true,
data: table,
coordinate: {
sheetId: sheet,
rowIndex: 2,
columnIndex: 0,
},
},
},
],
};
Sheets.Spreadsheets.batchUpdate(req, ss.getId());
}
You want to put a HTML table to "the next available row" using Sheets API with Google Apps Script as appending.
If my understanding is correct, how about this answer?
Modification point:
In your case, you can use both Sheets API and Spreadsheet service. Using this, in order to append the table using Sheets API, you can use getLastRow() of Spreadsheet service. And please use the value retrieved by getLastRow() to rowIndex.
When this is reflected to your script, it becomes as follows.
Modified script:
function pasteRequisicaoHtml(table) {
var ss = SpreadsheetApp.openById("1J_7GZ1C7pgHuRsdfsdfsdfsdf");
var sheet = ss.getSheetByName('Sheet5'); // Modified
var req = {
requests: [{
pasteData: {
html: true,
data: table,
coordinate: {
sheetId: sheet.getSheetId(), // Modified
rowIndex: sheet.getLastRow(), // Modified
columnIndex: 0,
},
},
}, ],
};
Sheets.Spreadsheets.batchUpdate(req, ss.getId());
}
References:
getLastRow()
GridCoordinate
Added:
In this sample script, the header row is deleted after the table is append. In this case, it supposes that the header row is one row.
function pasteRequisicaoHtml(table) {
var ss = SpreadsheetApp.openById("1J_7GZ1C7pgHuRsdfsdfsdfsdf");
var sheet = ss.getSheetByName('Sheet5'); // Modified
var lastRow = sheet.getLastRow(); // Added
var req = {
requests: [{
pasteData: {
html: true,
data: table,
coordinate: {
sheetId: sheet.getSheetId(), // Modified
rowIndex: lastRow, // Modified
columnIndex: 0,
},
},
}, ],
};
Sheets.Spreadsheets.batchUpdate(req, ss.getId());
sheet.deleteRow(lastRow + 1); // Added
}