javascript taking bit longer to execute - javascript

I am trying to achieve send sms whenever google spreadsheet gets updated with mobile no. but its taking too long to execute, surely I am making any mistake but can't find out the one. Requesting your help. below is my script.
function denver() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
ss.setActiveSheet(ss.getSheetByName("Form Responses 1"));
var sheet = SpreadsheetApp.getActiveSheet();
var dataRange = sheet.getRange("A2:M1000");
var data = dataRange.getValues();
for (i in data) {
var rowData = data[i];
var contactx = rowData[5];
var textx = rowData[8];
var Decision = rowData[12];
var EMAIL_STATUS = rowData[28];
var messages_url = "https://49.50.67.32/smsapi/httpapi.jsp?
username = maruti & password = maruti123 & from = MARUTI & to = " + contactx + " & text = " +
textx + "&coding=0&flash=2";
var options = {
"method": "post",
};
options.headers = {
"Authorization": "Basic " + Utilities.base64Encode("maruti:MARUTI")
};
UrlFetchApp.fetch(messages_url, options);
}
}

You're using a for loop over a section of the spreadsheet that seems very large, A2:M1000, and seem to be performing a number of memory accesses on each interation, similar with in. Iterating over data can be very time consuming and very likely negatively affects your run time, I'd be hesitant to use a for loop over a large data set. Fetch will also increase your run time as it takes longer to retrieve the information you're asking for. If I were you I would break this into separate functions that look at more specific ranges

Related

Get Google Emailer Script To Run For A Specific Set of Tabs

I have an emailer script that I would like to run for specified tabs and also make sure it skips any rows with blank values as it currently seems to break down as soon as it hits a blank row.
I have successfully built the script to work for one tab, but it seems to break down as soon as I try and get it to work for multiple tabs.
function reminders() {
var ss = SpreadsheetApp.openById("SHEET-ID");
var sheet = SpreadsheetApp.setActiveSheet(ss.getSheetByName(("sheet_1","sheet_2","sheet_3")));
var editedCell = sheet.getActiveRange().getColumnIndex();
var dataRange = sheet.getDataRange();
var data = dataRange.getValues();
var text1 = 'Insert body of email here';
for (var i = 1; i < data.length; i++)
(function(val) {
var row = data[i];
var recipient = row[4];
var name = row[2];
var replyto = 'reply_to#email.com';
var body = 'Dear' + ' ' + name + ',' + '\n\n' + text1;
var subject = 'Hello World';
GmailApp.sendEmail(recipient, subject, body, {from:'reply_to#email.com', replyto:'reply_to#email.com'});
})(i);
}
This currently works for sheet_1 but does not work for sheet_2 or sheet_3.
Does anyone have any suggestions for how I can improve this script to send to multiple sheets and also skip blank rows?
You want to send emails using the values of column "C" and "E" from the Spreadsheet.
You want to run your script for the sheet names of "sheet_1", "sheet_2" and "sheet_3".
You want to skip the rows which have no values of the column "C" and/or "E".
If my understanding is correct, how about this modification?
Modification points:
It seems that when var sheet = SpreadsheetApp.setActiveSheet(ss.getSheetByName(("sheet_1","sheet_2","sheet_3"))); is run, only "sheet_3" is retrieved.
In your case, I think that setActiveSheet() might not be required to be used.
Number of arguments of getSheetByName(("sheet_1","sheet_2","sheet_3")) is one.
When you want to use multiple sheets, please use each sheet name in the loop.
var editedCell = sheet.getActiveRange().getColumnIndex(); is not used in your script.
val of (function(val) { is not used in your script.
When you want to skip the empty rows, please put the if statement before GmailApp.sendEmail(). By this, the error is removed at GmailApp.sendEmail().
When above points are reflected to your script, it becomes as follows. Please think of this as just one of several answers.
Modified script:
Please copy and paste the following modified script to the script editor.
function reminders() {
var sheets = ["sheet_1","sheet_2","sheet_3"]; // Please set the sheet names here.
var ss = SpreadsheetApp.openById("SHEET-ID");
for (var s = 0; s < sheets.length; s++) {
var sheet = ss.getSheetByName(sheets[s]);
var dataRange = sheet.getDataRange();
var data = dataRange.getValues();
var text1 = 'Insert body of email here';
for (var i = 1; i < data.length; i++) {
var row = data[i];
var recipient = row[4];
var name = row[2];
if (!recipient || !name) continue; // Here, the empty rows are skipped.
var replyto = 'reply_to#email.com';
var body = 'Dear' + ' ' + name + ',' + '\n\n' + text1;
var subject = 'Hello World';
GmailApp.sendEmail(recipient, subject, body, {from:'reply_to#email.com', replyto:'reply_to#email.com'});
}
}
}
Note:
In this modified script, when "recipient" or "name" are not existing, the row is skipped.
When you send a lot of emails, please be careful the quotas of "Email read/write". You can see it at here.
References:
getSheetByName(name)
Quotas for Google Services
If I misunderstood your question and this was not the result you want, I apologize.

Looping through data and setting IndexMatch formula based on cell value - too slow because of .getValue()

I have a code which loops through my rows and depending on what the value is in Column 2, returns different types of IndexMatch formulas. My code works very well and puts the formulas in the relevant columns, however it is very slow.
I get a message that .getValue() is very heavy and therefore slows down the code.
Now I need to figure out how to improve the speed of the code but since I am new to coding, I am not particularly sure how to go at this problem.
Here is what I have:
function setFormulas() {
var ss = SpreadsheetApp.getActiveSpreadsheet(); //gets the workbook being used
var sheet = ss.getSheetByName("Open Requests"); //gets the active worksheet
var sheetnametoWatch ="Open Requests"; //defines sheet
var columnnumbertoWatch = 14
var valuetoWatch = ""
var CostCenter = "'Open Requests'!"
var lastrow = sheet.getLastRow();
var datarange = sheet.getRange(11,2,lastrow -1,50).getValues()
var row = 10
for (i=0;i<datarange.length;i++){
var rowID = 10 + i + 1
if (datarange[i][0] == "CC"){
var addedCell = '=CONCATENATE(F'+rowID+',N'+rowID+',K'+rowID+')';
sheet.getRange(row + i+1,35).setFormula(addedCell);
var MatchedCell = '=INDEX(Input!$Q:$Q,MATCH('+CostCenter+'$AI$'+rowID+',Input!$K:$K,0))';
sheet.getRange(row + i+1,17).setFormula(MatchedCell);
sheet.getRange(row + i+1,18).setValue("kristin.j#ni.com")
}
else if (datarange[i][0] == "CC + TM1"){
var addedCell = '=CONCATENATE(F'+rowID+',N'+rowID+',K'+rowID+')';
sheet.getRange(row + i+1,35).setFormula(addedCell);
var MatchedCell = '=INDEX(Input!$Q:$Q,MATCH('+CostCenter+'$AI$'+rowID+',Input!$K:$K,0))';
sheet.getRange(row + i+1,17).setFormula(MatchedCell);
sheet.getRange(row + i+1,18).setValue("kristin.j#ni.com")
}
else if (datarange[i][0] == "GC"){
sheet.getRange(row + i+1,18).setValue("kristin.j#ni.com")
}
}
}
So as you can see, I am looping through the data and then depending on whether the column = CC, CC+TM1, GC it will set other cells equal to the relevant formula.
It would be great if somebody can help me in speeding up this process.
I'm having some trouble following exactly what the code does, but at a high level, I think what you want to do is this: instead of setting formulas for particular cells as you cycle through your for loop, use the loop to figure out which cells should be set to which formulas and store that information. Then, at the end of the for loop, call sheet.getRange(x,y).setFormula(Formula); just a few times, perhaps once for each formula.
Does that seem like it could work?

Timing Tool for work

I have built a tool for timing indirect workers, it consists of a start and stop button which both place a time stamp into the google sheet and then calculates the difference to record a time. It works great however when I share it with some people it does not allow them to use it saying that they do no have access to run the script. If they open script editor they can manually run it however that will no fly because I will be sending this out to approximately 50 people.
Here is the code and start and stop are two different scripts. Please let me know if I am missing something and I appreciate the help. Thanks
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet()
var start = new Date();
function StartScript() {
var last = ss.getLastRow();
ss.getRange(last+1,1).setValue(last+1)
var source = ss.getRange(last+1,1).getValue();
source = Number(source);
if (source <= 16) {
ss.getRange(last+1,2).setValue(start);
}
else {
ss.getRange(last+1,2).setValue("Stop Timing");
}
}
function stop() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var date = new Date();
var last1 = ss.getLastRow();
ss.getRange(last1, 3).setValue(date);
var lastrow = ss.getLastRow()
ss.getRange("D" + (lastrow)).setFormula("=C" + (lastrow) + "-B" + (lastrow));
}

If/Else Statement not working to send different emails

I am trying to write a script in google sheets that will send one of two different emails based on the response to a multiple choice question. I can get my if/else statement to send either one or the other of the emails but it will not recognize the text of the multiple choice answer and send the correct email.
Here is the full script:
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 1;
// Fetch the range of cells A2:B3
var dataRange = sheet.getRange(startRow, 1, numRows, 8)
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var title = row[1]; // First column
var startDate = row[3]; // Second column
var endDate = row[4];
var description = row[2];
var location = row[6];
var eventImport = row[5];
var emailAddress = row[7];
var multchoice = row[8];
if (multchoice == "Part Time") {
var subject = "New Hire Part Time Email - " + startDate;
var emailBody = "Congradulations"
var htmlBody = "Congradulations! Part time person"
MailApp.sendEmail (emailAddress, subject, emailBody);
} else {
var subject = "New Hire Appointment - " + startDate;
var emailBody = "Congratulations! We are excited"
var htmlBody = "Congratulation! </i><br/> <br/> We are excited"
MailApp.sendEmail(emailAddress, subject, emailBody);
}
}
}
I believe the problem is here:
if (multchoice == "Part Time")
Any help is greatly appreciated! I am a novice
It looks like you are assigning your variables starting with '1' I stead of '0'. Start assigning them with 0 and counting up.
Without an example sheet to use, I won't be able to do a whole lot of debugging for you.
However, Apps Script comes with it's own debugger. Select the function you wish you debug and click the Little bug icon beside the play button.
Click on the sidebar where you want to set a breakpoint, where the code will stop executing.
Once it hits that breakpoint you can see all the variables currently within your scope. So the array, value, and i variables are visible to you.
Use this to your advantage and debug your code to find out where the issue is. Alternatively, you can use Logger.log() to log values at certain points within your code and then read back through the logs to try and determine where the problem lies.
The problem is not with your if/else statement. The problem is with how you are assigning your variables from your row[] array. While you use regular numbers in the getRange() function, the range that is returned is an array of those cells. Arrays always start with an index of [0]. Change var multchoice = row[8] to var multchoice = row[7] and your if/else statement will work (you'll want to change all of your other references, too).

Google Spreadsheet App Script will not wait for results to load

I have a small script and what I'm trying to do is to write one value from 'Sheet 1' to 'Sheet 2'. Wait for the results to load and compare the cells to see if it is above 10% or not. I have some =importhtml functions in the spreadsheet and it takes along time to load. I've tried sleep, utilities sleep, and flush. None have been working, maybe because I might be putting it in the wrong area..
function compareCells() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var listSheet = ss.getSheetByName('Stocks');
var dataSheet = ss.getSheetByName('Summary');
var listSheetLastRow = listSheet.getLastRow();
var currRow = 1;
for (i = 1; i <= listSheetLastRow; i++) {
if (listSheet.getRange(1, 3).getValue() == 'asd') {
var ticker = listSheet.getRange(currRow, 1).getValue();
dataSheet.getRange(5, 4).setValue(ticker);
var value1 = dataSheet.getRange(15, 4).getValue();
var value2 = dataSheet.getRange(22, 4).getValue();
SpreadsheetApp.flush();
if (value1 > 0.10 && value2 > 0.10) {
listSheet.getRange(currRow, 8).setValue('True');
listSheet.getRange(currRow, 9).setValue(value1);
listSheet.getRange(currRow, 10).setValue(value2);
} else {
listSheet.getRange(currRow, 8).setValue('False');
}
} else {
Browser.msgBox('Script aborted');
return null;
}
currRow++;
}
}
If it is not important that you use the =IMPORTHTML() function in your sheet, the easiest way to do this will be to use UrlFetchApp within Apps Script. Getting the data this way will cause your script to block until the HTML response is returned. You can also create a time-based trigger so your data is always fresh, and the user will not have to wait for the URL fetch when looking at your sheet.
Once you get the HTML response, you can do all of the same processing you'd do in Sheet1 within your script. If that won't work because you have complex processing in Sheet1, you can:
use UrlFetchpApp.fetch('http://sample.com/data.html') to retrieve your data
write the data to Sheet1
call SpreadsheetApp.flush() to force the write and whatever subsequent processing
proceed as per your example above
By handling these steps sequentially in your script you guarantee that your later steps don't happen before the data is present.
I had a similar problem but came up with a solution which uses a while loop which forces the script to wait until at least 1 extra column or 1 extra row has been added. So for this to work the formula needs to add data to at least one extra cell other than the one containing the formula, and it needs to extend the sheet's data range (number of rows or columns), for example by adding the formula to the end of the sheet, which looks like what you are doing. Every 0.5 seconds for 10 seconds it checks if extra cells have been added.
dataSheet.getRange(5, 4).setValue(ticker);
var wait = 0;
var timebetween = 500;
var timeout = 10000;
var lastRow = dataSheet.getLastRow();
var lastColumn = dataSheet.getLastColumn();
while (dataSheet.getLastColumn() <= lastColumn && dataSheet.getLastRow() <= lastRow){
Utilities.sleep(timebetween);
wait += timebetween;
if (wait >= timeout){
Logger.log('ERROR: Source data for ' + ticker + ' still empty after ' + timeout.toString() + ' seconds.');
throw new Error('Source data for ' + ticker + ' still empty after ' + timeout.toString() + ' seconds.');
}
}
In case if you are getting these two values (
var value1 = dataSheet.getRange(15, 4).getValue();
var value2 = dataSheet.getRange(22, 4).getValue();
) after the =importhtml call, you have to add sleep function before these two lines of code.
You also can have a loop until you get some values into the range from =importhtml call and add some sleep in the loop. Also note that as of April 2014 the limitation of script runtime is 6 minutes.
I also found this link which might be helpful.
Hope that helps!

Categories