Google App Script - loops not executing - google-apps-script

I want to create a function that will iterate over every sheet until a given sheet. The function receives the name of that last sheet as an argument.
function getUntilMonthSavings(month) {
var spreadsheet = SpreadsheetApp.getActive();
var monthSheet = spreadsheet.getSheetByName(month);
var allSheets = spreadsheet.getSheets();
var sheetNumber = monthSheet.getIndex();
var totalSavings=0;
for (var i = 1; i < monthSheet; i++){
totalSavings = totalSavings + allSheets[i].getRange("I20").getValue();
}
return totalSavings;
}
My problem is that what is returned is always 0. I've also returned i to check if it is being iterated, but it returns 1 even when the sheet index is greater than 1.
I'm sure to be doing some kind of basic blunder, but I'm quite at a loss as why this code is not working.

MonthSheet is an object and not something you can compare i to in your loop. You need the actual index of the sheet referred to.
Try:
for (var i = 0; i < monthSheet.getIndex(); i += 1) {

Related

Google sheet function into Google script function

I'm using Google Sheets function for analyze some data, but even if i have not huge database, the sheet is lagging with my function. The function is:
=ARRAY_CONSTRAIN(ARRAYFORMULA(SUMIF(IF(A2:A10000="Received",ROW(A2:A10000),""), "<="&ROW(A2:A10000), B2:B10000)+G1-SUMIF(IF(A2:A10000="Given",ROW(A2:A10000),""), "<="&ROW(A2:A10000), B2:B10000)),COUNTA(B2:B10000),1)
Is it possible to use this function via Google script so as not to overload the sheet?
Example sheet: https://docs.google.com/spreadsheets/d/1UeIXFVsP5hevC20D04juTstBbfViYhWUIp6VRst_Nu4
Try this script. It worked correctly in my copy.
The purpose is to take previous value and add or subtract new value depending on the condition in column A
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getActiveSheet();
var previous = s.getRange('G1').getValue(); //ger vaule from last month
var valuecount = s.getLastRow() ; // defines number of rows
for (let i = 1; i < valuecount; i++) { //starts loop
var direction = s.getRange(i+1 , 1).getValue();
if (direction == 'Received') {
previous = previous + s.getRange(i+1 , 2).getValue() ;
}
else
{previous = previous - s.getRange(i+1 , 2).getValue() }
s.getRange(2,4,valuecount).getCell(i,1).setValue(previous);
}
}

Clueless - Exceeding execution time

I took this code from a sheet that was provided to me to use, but it's inefficient and times out before completing. I'm trying HARD to re-write it in a super simple format to get it to complete within the time limit. This is what I started with:
function addTo() {
var ss = SpreadsheetApp.getActiveSheet();
// Style 1
// Size 2
var num1 = ss.getRange("AL2").getValue();
var num2 = ss.getRange("O2").getValue();
ss.getRange("O2").setValue(num1+num2);
ss.getRange("AL2").clearContent();
// Size 4
var num1 = ss.getRange("AM2").getValue();
var num2 = ss.getRange("P2").getValue();
ss.getRange("P2").setValue(num1+num2);
ss.getRange("AM2").clearContent();
Then repeat that about 200 times. Someone suggested processing as a range instead. That makes sense and should result in a faster process. But I'm having trouble writing it. This is what I have so far (it's not working though):
function addallatOnce() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var startrange = ss.getRange("Inventory Received!B2:U48");
var addrange = ss.getRange("Inventory Received!Y2:AR48");
var complete = startrange+addrange
ss.getRange("Inventory Received!B50:U96").setValues(complete);
}
I don't usually write code, I can understand what I'm reading, but I don't know anything about writing it. Help would be greatly appreciated. Thank you in advance.
With Google Script
Google has some excellent documentation on optimizing code. In this case you can perform batch operations using arrays. First feed the spreadsheet data into the arrays using the getValues() function on the ranges. Note that getValues() returns a 2D array of the values within the range. Loop through all the values and add them together, value by value. Then assign the desired range the value of the complete array.
function addallatOnce() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var startrange = ss.getRange("Inventory Received!B2:U48").getValues();
var addrange = ss.getRange("Inventory Received!Y2:AR48").getValues();
var complete = addrange;
var row = 0;
var col = 0;
for (row = 0; row < complete.length; row++) {
for (col = 0; col < complete[0].length; col++) {
complete[row][col] = addrange[row][col] + startrange[row][col];
}
}
ss.getRange("Inventory Received!B50:U96").setValues(complete);
}
Without Google Script
Put the following formula in cell B50 of Inventory Received:
=ARRAYFORMULA(B2:U48+Y2:AR48)
See documentation here.

How can I check one value against another value in my Google Sheet and then query properties of the cell with the matching value?

I want to check values from a JSON URL against values within a defined range in my Google Sheet.
Should there be a match, I would like to query the properties of the cell containing the matching value (its row, its column, etc.)
How can I do this within Google Apps Script?
Everything you need to know about Spreadsheet operations in Apps Script can be found in Overview and SpreadsheetApp. You can start from there. For example, the methods to query properties like row and col are getRow and getColumn
Never mind. Got to my answer myself.
var i = 0;
// Bringing in the data from the third-party into Google Sheets.
var groupJSON = UrlFetchApp.fetch('<ANY-JSON-URL>');
var groupObjectRaw = JSON.parse(groupJSON);
// var groupObject = groupObjectRaw[0]; <--optional, for my use only
var membersGroupForm = groupObject.data['member'];
var projectsGroupForm = groupObject.data['project'];
var hoursGroupForm = groupObject.data['hours worked'];
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Details');
var membersRange = ss.getRange('Details!A:A');
var membersSheet = membersRange.getValues();
var projectsRange = ss.getRange('Details!1:1');
var projectsSheet = projectsRange.getValues();
function getRowNumber() {
for (i; i < membersSheet.length; i++) {
if (membersSheet[i][0] == membersGroupForm) {
return i + 1;
}
}
}
var rowNumber = getRowNumber(i, membersSheet, membersGroupForm);
Logger.log(rowNumber);
function getColumnNumber() {
for (var row in projectsSheet) {
for (var col in projectsSheet[row]) {
if (projectsSheet[row][col] == projectsGroupForm) {
return parseInt(col) + 1;
}
}
}
}
var columnNumber = getColumnNumber(projectsSheet, projectsGroupForm);
Logger.log(columnNumber);
var cell = ss.getRange(rowNumber, columnNumber);
cell.setValue(hoursGroupForm);

Google Script Optimization

I have a sheet in which IDs are saved. Now occasionally I need to read these IDs and check if other values(Name) in the sheet still fits the ID. The code I have is:
var name = sheet.getRange(line,row).getValue();
var id = sheet.getRange(line,10).getValue();
if(name!== "" && id === "")
{
try
{ get an ID}
Now from what I read I know that calling each cell value seperately takes way more time. However I am not sure how to apply getValues to have these cases fixed.
Basically the same problem in a different dress I have with the following code:
var id = sheet.getRange(line,row).getValue();
if(id!== "" && id!="Not Found" && id!="Not Found old")
{
var url = "some api url "+id+"api key";
try
{
var str = UrlFetchApp.fetch(url).getContentText();
So how do I use get values to check every ID I get. I guess I would have to use some sort of
foreach(id)
or a
for(i= 0; i <= id.range; i++)
{
use id[i] to blablabal
}
But I have no idea how to implement it, any ideas?
Is there maybe even a different, more efficient way?
After calling getValues you get a double array, like [[valueA1, valueB1], [value A2, value B2]]. Process it in a for loop, which may be a double loop if all row/column combinations are involved. Keep in mind that spreadsheet uses 1-bases indexing but in JavaScript they are 0-based. Often, the top row is headers, so it's omitted from the loop below.
function processData() {
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getDataRange(); // all of data. could be some part of it
var values = range.getValues();
for (var i = 1; i < values.length; i++) { // skipping with header row
for (var j = 0; j < values[0].length; j++) {
if (condition) {
// do something to values[i][j];
}
}
}
range.setValues(values); // put updated values back
}
If the data of interest is in, say, column D, then you can decide to fetch only that column. For example:
function fetchStuff() {
var sheet = SpreadsheetApp.getActiveSheet();
var lastRow = sheet.getLastRow();
var range = sheet.getRange(1, 4, lastRow, 1); // all of column D, note 1-based indexing
var values = range.getValues();
for (var i = 1; i < values.length; i++) { // skipping header row
if (condition) {
var str = UrlFetchApp.fetch(values[i][0]).getContentText();
// do something
}
}
}
Keep in mind that fetch is by far the slowest operation here, and that it is subject to quotas. Use Utilities.sleep(ms) to avoid invoking services too often, and keep track of how much data you are asking the script to fetch.

Inserted formula not doing anything

I have put this little script together to insert an if(vlookup) formula into a spreadsheet but even though it is running it isn't inserting anything into the spreadsheet. Can anyone suggest what I have missed off or overlooked please?
Or is there an easier way to do this with an array? I'm still fairly new so not sure how I would execute that successfully.
function idSiteCoordinator(){
var SS = SpreadsheetApp.getActiveSpreadsheet();
var shLog = SS.getSheetByName("LOG");
//declare how many rows to interrogate (to the last row)
var lastRow = shLog.getLastRow();
var startRow = 2;
for (var i=startRow; i<lastRow+1; i++)
{
//Grab the values for LocationCodes
var siteCo = shLog.getRange([i],[12]).getValue();
//Enter formula
if(siteCo = ""){
siteCo.setFormula('=if(E'+[i]+'="08 - Maintenance Request System",LocationCodes!$E$33,vlookup(D'+[i]+',LocationCodes!$D$3:$E$32,2,false))');
}
}
}
You cannot apply the method setFormula to the value, but to the range. Change this on your method:
var siteCo = shLog.getRange([i],[12]);
if(siteCo.getValue() == ""){
siteCo.setFormula('=if(E'+[i]+'="08 - Maintenance Request System",LocationCodes!$E$33,vlookup(D'+[i]+',LocationCodes!$D$3:$E$32,2,false))');
}