getValues and setValues with different ranges - google-apps-script

I am having a Google script that sets values of specific ranges from sheet B to sheet A on a button press.
The code I have works, but it takes about 40 seconds due to the high amount of getValue/setValue usage I guess.
The code seen below is only a snippet. It goes on like this about four times as shown.
I already have a nice solution for copying values from one large range (say A1:Z30 via loops but I can not figure out a solution for this matter here.
Your support is very much appreciated. Thank you in advance.
ratenprogrammmain.getRange("E1:E18").setValues(vorlage.getRange("E13:E30").getValues());
ratenprogrammmain.getRange("B2").setValue(vorlage.getRange("B14").getValue());
ratenprogrammmain.getRange("B5").setValue(vorlage.getRange("B17").getValue());
ratenprogrammmain.getRange("A21").setValue(vorlage.getRange("A33").getValue());
ratenprogrammmain.getRange("B25").setValue(vorlage.getRange("B37").getValue());
ratenprogrammmain.getRange("A28:G33").setValues(vorlage.getRange("A40:G45").getValues());
ratenprogrammmain.getRange("H35").setValue(vorlage.getRange("H47").getValue());

Three ideas how to make your code more effiient
If your sheets are located in the same Spreadsheet you can use the copyTo() method for ranges.
Apps Script Best Practices provides samples how to use batch operations to make you code faster and more efficient.
Advanced Sheets Service allows you to use the Sheets API batchUpdate Request CopyPasteRequest

Related

How to solve the limitation of IMPORTRANGE formula in google sheet?

I have 50 google sheet files for 50 students. They need to key in their answers in their own google sheet file when they are asked to do so. I have a main google sheet to consolidate their data by using IMPORTRANGE formula. This is my formula:
=QUERY({IMPORTRANGE(...);IMPORTRANGE(...);IMPORTRANGE(...);...},"Select * where Col1 is not null")
I will have 50 IMPORTRANGE in the formula. So as expected, the main google sheet is very lag when the 50 students start to key in their answers at the same time. Sometimes, the formula will show #Value when all the students started to answer the questions at their own google sheet file. I need to keep refreshing the main google sheet so that the data will come out, but it will disappear again in a short while then I need to refresh it again (although it will settle down once most of the students finished answering the questions).
I know that using IMPORTRANGE is really not an efficient way to consolidate their answers in main google sheet file but I don't have other better way.
I tried to write a script so that they can send in their data by clicking the button assigned with the script. However, all the students need to go through the authorization process when they run the script for the first time. They don't know how to proceed when they saw the authorization process (not very good in using computer).
May I know is there any ways or tricks that I can use to solve the IMPORTRANGE issue? Or there are some way to write the script where we are not required to go through the authorization process when we run the script for the first time?
Hope to get some advice and help on this as I couldn't find a better way from Google already. Any help will be greatly appreciated!
If I understood correctly what you are looking is that your spreadsheet show in real-time the data being entered simultaneously on 50 different spreadsheets. I'm afraid that Google Sheets is not the right tool for what you are trying to do the way that you are trying to do it. Basically you have two options : change it or use a different tool.
It's not a good idea to have and array of multiple IMPORTRANGE functions that are being edited simultaneously because while the official docs says that IMPORTRANGE functions are updated every 30 minutes when the source and the spreadsheet having formula are opened at the same time the import is done practically immediately and could happen multiple times during the recalculation making causing it to start over an over again.
Replacing the above array by script might help only if you are open to not have the destination spreadsheet updated on real time as scripts are slow.
Replacing the above array by a program that uses the Google Sheets API also might help only if you are open to not have the destination spreadsheet updated on real time as the spreadsheet refresh.
Regarding running a script without requiring authorization that is only possible when using simple triggers and / or removing all the scopes that require authorization to run. Please bear in mind that you might create installable triggers to run other using the authorization of the user who creates them.
Related
Combining multiple spreadsheets in one using IMPORTRANGE
Why do two users sometimes see different values from importrange?
Multiple IMPORTRANGE
Using that many IMPORTRANGE formulas is definitely a bad idea. What I'd suggest you to do:
keep a list of all your student spreadsheet in your main document
write a script that will browse through all of the spreadsheets from that list and copy/paste values into your main document
create a time based trigger that will run the script every X minutes (or hours), depending on how accurate you want the results to be
This is a simple solution, but efficient. Depending on the amount of data and number of students/spreadsheets you may consider other solutions (like writing a cloud function that will do the same as the script) but I think this will work for your use case

How can I trigger a function to multiple spreadsheets from a single script?

I have to develop a spreadsheet for each department within a company (around 60 in total), all of those have to be identical and are going to populate a master spreadsheet. I have a similar case in which the function triggers when a user inputs data as an onEdit(e) function trigger. The problem is, that those "backend" sheets (which are hidden and protected) only can be triggered by me manually.
Due to the nature of the first project I mentioned, I need to trigger some functions on those 60 spreadsheets and their respective sheets in order to push updates to all of them as I keep developing and improving the structure and calculations. Those functions might be destined to set Formulas, read and write data, etc.
I know how to link scripts files as a library, the developer mode, etc, but I ignore how to trigger a function in multiple places from a single one. Any help or hint would be great guys :)
Love y'all
I didn't find any way to activate triggers from a script. Some workaround ideas you could implement are these:
1) Instead of using an onEdit trigger in each spreadsheet you could use a Clock trigger [1] which is an Installable trigger [2]. This way the functions could get activated at a certain time or every certain time.
2) Put all the scripts together in a single script. You can use the openById() function [3] to obtain and manipulate the different spreadsheets.
[1] https://developers.google.com/apps-script/reference/script/clock-trigger-builder
[2] https://developers.google.com/apps-script/guides/triggers/installable
[3] https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet-app#openById(String)

In google sheets can I wrap a standard function in a custom function to control when it is run?

I originally asked this on WebApps, thinking that I was just missing a google trick. There I received the answer that it would require a custom function.
https://webapps.stackexchange.com/questions/129068/recalculate-google-sheet-on-demand
Here is my original question:
I have the following formula in a sheet:
=if(E1="HOLD",,query(Cust_Orders!B6:Z5000,"Select Y,G,I,H,K where H>0 "))
With E1 being a drop down with values HOLD and FETCH
The recalculation when I go to FETCH takes about 13 seconds.
But when it is in HOLD, the query doesn't exceute, and everything goes
blank. Not what I want.
I'm trying to avoid recalculating this query every time I make a
change in the Cust_Orders range, but keep the old values, as two
different pivot tables that are viewed by other people are dependent
on it.
Google spreadsheet recalc settings all are 'on change and foo'
Is there a way to do this?
Custom functions only update when one of their parameters changes. So if the function only depends on the HOLD/FETCH cell, but executes the formula is the query cell, I think I win.
My research:
This answer google sheets custom function built-in function is specific in telling the OP how to do what he wants in the script language. I suspect that rewriting the query in appscript would not be a net win.
This link Using Bound Google Scripts to Generate a Query Object
was proposed as a solution, but this in effect is rewriting my built-in function within the script. I want to use scripts as rarely as possible, and as generically as possible, as it makes long term maintenance and modification easier.
The query function above is an example. I am looking for a more general solution that allows me to use an arbitrary formula using the same script.
This discussion on google product forums: https://support.google.com/docs/forum/AAAABuH1jm01F-8MzzCxbY/?hl=en&gpf=%23!topic%2Fdocs%2F1F-8MzzCxbY says you can't call built-ins from scripts. But the question is almost 4 years old.
I have asked this question there too, but generally asking on Google Product Forums is a Hail Mary.
A viable solution:
An example of a script calling a built-in function.
A link to an add-on that allows recalculation of a range to be toggled on/off
A more general method than custom formulas to control recalc.
I do NOT want a script that emulates the desired built-in inside the script.
A more general method than custom formulas to control recalc.
What I'm doing on project for a client is to have the "expensive" formulas saved as variables on the script and have buttons to freeze/unfreeze the certain ranges (those that have a high impact on the recalculation time.
The "unfreeze" button adds the formulas to the spreadsheet
The "freeze" button put the formulas results over the range used by the formulas
There is a document property that stores the frozen/unfrozen spreadsheet state
A sidebar is used to show the buttons the spreadsheet status.
An example of a script calling a built-in function.
Scripts can get values, display values, formulas, and other stuff but they can not call built-in functions.
In the case of my client, they have one array formula (IMPORTRANGE, QUERY, FILTER, ARRAYFORMULA, etc) by sheet, all the formulas that are been included are on A1. The formulas are saved in an array of objects of the following form
var formulas = [
{
name:'Sheet1',
address:'A1',
formula:'=IMPORTRANGE(...)'
}
]
The address property, is included for future improvements.
The key code lines of the "freeze" function are
var dataRange = sheet.getDataRange();
dataRange.copyTo(dataRange, SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
Please note that the above lines copy-paste-as-values the whole data range.
The key code lines of the "unfreze" function are
formulas.forEach(function(item){
var sheet = spreadsheet.getSheetByName(item.name);
sheet.clear();
sheet.getRange(item.address).setFormula(item.formula);
});
Please note that the above lines clear the whole sheet.

Delay in changing Google Spreadsheet content via Google apps Script?

I am totally new to Google-apps-script and this may be very poor question
I am making a basic setup using google forms and google apps script
From the responses of form I change my content in Google Spreadsheet accordingly
For example my query from form needed 10000 records to be selected and produced in whole another spreadsheet
I just wanted to know that is there some kind of delay introduced when I set and get values of any cell of spreadsheet on such a large scale? If so on what it depends and how as a programmer can I remove or optimize them?
Thanks is advance!
The Best Practices article by Google is the primary reference for this. The most important advice is to minimize the number of calls to spreadsheet methods by batching operations. So, select a range that contains all the records you need, get them all at once with getValues, process without further interaction with the spreadsheet, and output the result using setValues.
If you follow this advice, 10000 records is still a reasonable amount of data to process by a script.

Automatically keep one sheet synchronized with another

I have a Google Sheets that I'm working with, and for reasons I'd rather not get into here I need to keep an updated copy of it in a second location. The original spreadsheet has two sheets/pages, I only need to copy from the second sheet/page to the first sheet/page of the new spreadsheet.
I have a server that can accomplish this if an API is necessary. I don't need an exact script to do it, but pointing me in the right direction would be very helpful. I'm most familiar with Python and PHP if they're needed.
I'm sure there is an easier way to do it using Apps Script, but if you want something that works in the short-term while you learn Apps Script, you can use the IMPORTRANGE function and Sheets exclusively.
=IMPORTRANGE("SpreadsheetKey","Sheet!Range")
Example:
I created a sheet called OriginalSheet and in A1:A5 put the numbers 1 through 5.
Next, I created a separate sheet called NewSheet and in cell A1, I put the the following function (with appropriate values for my OriginalSheet filled in):
This method works for me. I'm in the process of learning Apps Script and will post a better method when I learn it :)