Google Sheets script hangs on getRange - google-apps-script

POST UPDATE:
Hi, at the end the problem was seemingly not related to the getvalue() itself but to the source, which was a range imported by an IMPORTRANGE formula. This formula was bugging. I do not really know why but I assume it was somehow related to the size of the spreadsheet. I have not been able to check this point. I tried to download the file without success. Finally, I have build a new spreadsheet. Things now seem to be working alright now. But still I’d like to now what happened to understand how to avoid it next time.
Anyway, thank you for your help.
ORIGINAL POST:
I experiencing problems with the getRange function in GAS. It's quite a simple code which was working normally until something (I do not know what) went wrong and then started to fail. I am just trying to gather a date value from a cell to use it afterwards to create an email.
I am trying to debug the code step by step by means of Logger and vars but I am struggling to figure out what happens when I try to getValue from the corresponding monocell range.
This below is the code I am trying currently:
// Retreive email receipts from Form submitted choice
function EmailUpdatefromForm()
{
var spreadsheet = SpreadsheetApp.openById("1ImOXXXXXxSDz8AqjMWtuSPtg7xMejqPpHQ9vwDnY");
var form = FormApp.getActiveForm();
var formResponses = form.getResponses();
var formlength = formResponses.length;
Logger.log(formlength);
var formResponse = formResponses[formResponses.length-1];
var itemResponses = formResponse.getItemResponses();
var itemlength = itemResponses.length;
Logger.log(itemlength);
for (var j = 0; j < itemResponses.length; j++) {
var itemResponse = itemResponses[j];
var emailto = itemResponse.getResponse();
Logger.log(itemResponse+" - "+emailto);
}
var email = (emailto? emailto[0] : "xxxxxxxxxxs#xxxxxxx.com");
var sheet = spreadsheet.getSheetByName("report");
var log1 = spreadsheet.getId(); //--> THIS CHECKPOINT WORKS AND GETS THE PROPER SS ID
var log2 = sheet.getSheetId(); //--> THIS CHECKPOINT WORKS AND GETS THE PROPER SHEET ID
var log3 = sheet.getRange(2, 1) //--> THIS CHECKPOINT WORKS ALTHOUGH I CANNOT SEE IF IT IS ACTUALLY POINTING TO THE PROPER CELL
var log4 = sheet.getRange(2, 1).getValues(); //--> THIS CHECKPOINT GETS STUCK\\
var updatedate = sheet.getRange(2,1).getValue(); //--> THIS IS WHAT I REALLY WANT TO DO
var PDFdate = Utilities.formatDate(updatedate, "GMT+1", "yyyyMMdd")
}
I have found several posts mentioning issues with getRange but I have not found any response really clarifying what's happening here and how to turn it around.
Thank you in advance for your support!

function EmailUpdatefromForm() {
var spreadsheet = SpreadsheetApp.openById("1ImOXXXXXxSDz8AqjMWtuSPtg7xMejqPpHQ9vwDnY");
var form = FormApp.getActiveForm();
var formResponses = form.getResponses();
var formlength = formResponses.length;
Logger.log(formlength);
var formResponse = formResponses[formResponses.length-1];
var itemResponses = formResponse.getItemResponses();
var itemlength = itemResponses.length;
Logger.log(itemlength);
for (var j = 0; j < itemResponses.length; j++) {
var itemResponse = itemResponses[j];
var emailto = itemResponse.getResponse();
Logger.log(itemResponse+" - "+emailto);
}
var email = (emailto? emailto[0] : "xxxxxxxxxxs#xxxxxxx.com");
var sheet = spreadsheet.getSheetByName("report");
var log1 = spreadsheet.getId();
var log2 = sheet.getSheetId();
var log3 = sheet.getRange(2, 1);
var log4 = log3.getValue();
var updatedate = log4;
var PDFdate = Utilities.formatDate(updatedate, "GMT+1", "yyyyMMdd")
}

Related

Copying Data from One Spreadsheet to Several Others with Array and For Loop - Repost as suggested did not solve

The following appears to work, however the code times out. A portion of the data is transferred to the 1st sheet of the loop and then the following error occurs: "Exception: Service Spreadsheets failed while accessing document with id "Y". CopyCmpstrs # Code.gs:33" For the purpose of the post, I removed the actual spreadsheetIDs.
The following has been suggested as a solution, however this only deals with data within the same spreadsheet and is a separate issue. The issue that I am having, I think, is that the dataset is large and the 2nd sheet being pasted to is freezing: Is possible to copy a data range from one spreadsheet to another?
Is possible to copy a data range from one spreadsheet to another?
function CopyCmpstrs() {
var DashboardSSID = "X";
var PaymentSSID = "Y";
var SalesSSID = "Z";
var FormsSSID = "A";
var ProductSSID = "B";
var InvoiceSSID = "C";
var TargetSSID = [PaymentSSID,SalesSSID,FormsSSID,ProductSSID,InvoiceSSID];
var ssSource = SpreadsheetApp.openById(DashboardSSID);
var CmpstrsSheet = ssSource.getSheetByName("Cmpstrs");
var CmpstrsSheetName = CmpstrsSheet.getName();
var RowCountSource = CmpstrsSheet.getRange(1, 2).getNextDataCell(SpreadsheetApp.Direction.DOWN).getRow();
var CustomerData = CmpstrsSheet.getSheetValues(1,1,RowCountSource,176);
var ArraySize = TargetSSID.length;
for (var i=0; i<= ArraySize; i++){
var TargetSS = SpreadsheetApp.openById(TargetSSID[i]);
var TargetSheet = TargetSS.getSheetByName(CmpstrsSheetName);
var MaxRow = TargetSheet.getMaxRows();
var MaxCol = TargetSheet.getMaxColumns();
var TargetFullRange = TargetSheet.getRange(1,1,MaxRow,MaxCol);
TargetFullRange.clearContent();
var TargetRange = TargetSheet.getRange(1,1,RowCountSource,176);
TargetRange.setValues(CustomerData);
}
}

Google Apps Script Error "Exception: Invalid argument: options. Should be of type: Map"

I'm trying to make a quick script to copy information from a series of spreadsheets into a single spreadsheet. I'm getting an error
"Exception: Invalid argument: options. Should be of type: Map".
I know very little about maps, and this error makes no sense to me.
function make_new_contact_lists() {
DriveApp.getFileById("1IZBpDno4MOBeiGJeIKd2ykHpCr2359jhcV_SJpSuQ94");
var ss = SpreadsheetApp.getActiveSpreadsheet();
SpreadsheetApp.setActiveSpreadsheet(ss);
var sheet = ss.getSheetByName("Sheet2")
ss.setActiveSheet(sheet);
var lr = sheet.getLastRow();
var range = sheet.getRange("A2:B" + lr).getValues();
var list = [];
list.push([range]);
for (i = 0; i < list.length; i++) {
var entry = list[i];
var name = entry[0];
var fileID = entry[1];
var newsheet =
SpreadsheetApp.openById("1IZBpDno4MOBeiGJeIKd2ykHpCr2359jhcV_SJpSuQ94");
SpreadsheetApp.setActiveSpreadsheet(newsheet);
/**-->This is where the error gets flagged**/
newsheet.insertSheet(name);
var newsheet2 = newsheet.setActiveSheet(name);
var file = SpreadsheetApp.getFileById(fileID);
var spreadsheet = file.setActiveSpreadsheet();
var current = spreadsheet.getSheetByName("Current Contacts");
spreadsheet.setActiveSheet(current);
var range2 = current.getRange("A1:G3").getValues();
current.setValues
}
}
Thank you for any help you can provide
Issue:
var range = sheet.getRange("A2:B"+lr).getValues();//[[a2,b2],..]
var list = [];
list.push([range]); //[[[[a2,b2],[a3,b3],..]]]
for (i=0; i < list.length; i++){
var entry = list[i];//[[[a2,b2],[a3,b3],..]]
var name = entry[0];//[[a2,b2],[a3,b3],..]
list is a 4D array and name is a 2D array. newsheet.insertSheet(name) expects name to be a string or object, whereas the script is providing a 2D array.
Solution:
Directly access range as a 2D array, which makes name a string
Snippet:
const range = sheet.getRange("A2:B"+lr).getValues();//[[a2,b2],..]
for (const i=0; i < range.length; i++){
var entry = range[i];//[a2,b2]
var name = entry[0];//"a2"
Some of your code simply does not make sense. You might be better of to start again with this:
function make_new_contact_lists() {
DriveApp.getFileById("1IZBpDno4MOBeiGJeIKd2ykHpCr2359jhcV_SJpSuQ94");
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName("Sheet2")
const lr = sh.getLastRow();
const vs = sh.getRange("A2:B" + lr).getValues();
const ss1 = SpreadsheetApp.openById("1IZBpDno4MOBeiGJeIKd2ykHpCr2359jhcV_SJpSuQ94");
for (i = 0; i < vs.length; i++) {
let entry = vs[i];
let name = entry[0];
let fileID = entry[1];
let nsh = ss1.insertSheet(name);
let ss2 = SpreadsheetApp.openById(fileID);
let csh = ss2.getSheetByName("Current Contacts");
let vs2 = csh.getRange("A1:G3").getValues();
//the rest of the code makes no sense
csh.setValues
}
}
And don't just make up methods go read the documentation about them paying attention to parameters and return values.

Filter gmails using timestamp

Am new dabbling with Google Apps Script; would like to ask if I'm in the right direction, and how to I manipulate time within the script.
I'm struggling in trying to maniuplate time values in Google App Script, basically I am able to pull the timestamp of each email sent, but I only want to paste into the spreadsheet email information that were recent, e.g. within 30minutes from script run time. This is to avoid pulling duplicate information.
Not sure if there is a currentTime() function here, or I have to create a new Date() object and do some calculations from there. Tried a few variations and nothing seemed to work proper.
Would appreciate any help in getting towards the right direction in doing this thank you!
function getDetails(){
var DEST_URL = "SHEET_URL"; //redacted for sensitivity
var DEST_SHEETNAME = "Test";
var destss = SpreadsheetApp.openByUrl(DEST_URL);
var destSheet = destss.getSheetByName(DEST_SHEETNAME);
var threads = GmailApp.search("FILTERS"); //filter settings redacted for sensitivity
for(var i = 0; i < threads.length; i++){
var messages=threads[i].getMessages();
for(var j =0; j < 1; j++){ //only take first message in thread
var message = messages[j];
var subject = message.getSubject() ;
var sentTimeStamp = message.getDate();
if(sentTimeStamp is within last 30minutes as of script run time){ //this is where i need help
var delimitString = subject.split("is sent");
var detailName = delimitString[0];
var lastRow = destSheet.getLastRow();
destSheet.getRange(lastRow + 1,1).setValue(detailName);
destSheet.getRange(lastRow + 1,2),setValue(sentTimeStamp);
}
}
}
}
You can convert timeStamp into ms seconds and then compare to the value of "30 s ago"
Sample:
var sentTimeStamp = message.getDate();
var now = new Date();
var ThirtyMinutesAgo = now-30*60*1000;
if(sentTimeStamp.getTime() < ThirtyMinutesAgo){
...
}
References:
newDate()
getTime()
Another idea would be to query for emails that you received the last 30 minutes.
Explanation:
You can get the emails that you received the last 30 minutes ago as a query in the GmailApp.search function. See this link to see what filters you can use.
This will get the last emails with keyword "FILTERS" that you received the last 30 minutes.
var ThirtyMinutesAgo = new Date();
ThirtyMinutesAgo.setMinutes(ThirtyMinutesAgo.getMinutes() - 30);
const queryString = `"FILTERS" newer:${Math.round(ThirtyMinutesAgo.getTime()/1000)}`
const threads = GmailApp.search(queryString); // threads the last 30 minutes
This approach is more efficient for two reasons:
You have less data (threads) to iterate over with the for loop.
You don't need to apply and if statement on every thread.
Solution:
function getDetails(){
var DEST_URL = "SHEET_URL"; //redacted for sensitivity
var DEST_SHEETNAME = "Test";
var destss = SpreadsheetApp.openByUrl(DEST_URL);
var destSheet = destss.getSheetByName(DEST_SHEETNAME);
// var threads = GmailApp.search("FILTERS"); //filter settings redacted for sensitivity
// new code
var ThirtyMinutesAgo = new Date();
ThirtyMinutesAgo.setMinutes(ThirtyMinutesAgo.getMinutes() - 30);
const queryString = `"FILTERS" newer:${Math.round(ThirtyMinutesAgo.getTime()/1000)}`
const threads = GmailApp.search(queryString); // threads the last 30 minutes
//
for(var i = 0; i < threads.length; i++){
var messages=threads[i].getMessages();
for(var j =0; j < 1; j++){ //only take first message in thread
var message = messages[j];
var subject = message.getSubject() ;
var sentTimeStamp = message.getDate();
var delimitString = subject.split("is sent");
var detailName = delimitString[0];
var lastRow = destSheet.getLastRow();
destSheet.getRange(lastRow + 1,1).setValue(detailName);
destSheet.getRange(lastRow + 1,2),setValue(sentTimeStamp);
}
}
}
}

Logging Google mail in Google sheet, Google Apps Script

HELP! I’m using a script I basically cribbed from Tom Woodward at Bionice Teaching to record email messages in a spreadsheet.
http://bionicteaching.com/auto-logging-email-via-google-script/
I need to add a column that collects any labels that have been attached to the messages. I need to get this done for my work, but I'm brand new to Google Apps Script and really need someone to hold my hand... Essentially doing it for me, then teaching me what it was you did. I really appreciate any help you can give me in any case. Thanks
Here is what I’m using:
function myFunction() {
//this is just the stuff that recognizes what spreadsheet you're in
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
var sheet = ss.getSheetByName("data"); //gets the right sheet
//this chunk gets the date info
var today = new Date();
var dd = today.getDate()-1;
var mm = today.getMonth()+1; //January is 0 DO NOT FORGET THIS
var yyyy = today.getFullYear();
var yesterday = yyyy + '/' + mm + '/' + dd;
//****************************************************
//searches your GMail for emails written after yesterday
var query = "after:" + yesterday;
var threads = GmailApp.search(query);
Logger.log('threads len ' + threads.length);
Logger.log(query);
for (var i = 0; i < threads.length; i++) {
var messages = threads[i].getMessages();
Logger.log(messages);
for (var m = 0; m < messages.length; m++) {
var supportStats = [];
//here's where you decide what parts of the email you want
var from = messages[m].getFrom(); //from field
Logger.log(from);
var time = messages[m].getDate();//date field
Logger.log(time);
var subject = messages[m].getSubject();//subject field
Logger.log(subject);
var body = messages[m].getPlainBody();//body field
Logger.log(body);
var mId = messages[m].getId();//id field to create the link later
var mYear = time.getFullYear();
var mMonth = time.getMonth()+1;
var mDay = time.getDate();
var messageDate = mYear + '/' + mMonth + '/' + mDay;
Logger.log('msg date ' + messageDate);
//decides what found emails match yesterday's date and push them to an array to write to the spreadsheet
if (messageDate === yesterday) {
supportStats.push(from);
supportStats.push(time);
supportStats.push(subject);
supportStats.push(body);
supportStats.push('https://mail.google.com/mail/u/0/#inbox/'+mId); //build the URL to the email
SpreadsheetApp.getActiveSheet().appendRow(supportStats); //writes to the spreadsheet
}
}
}
}
Here is the results I'm getting... Perfect!
Except I'd like one more column that adds the labels that are on each message. How do I do that?
spreatsheet results of Google Apps script mail->sheet
You can use this:
var labels = threads[i].getLabels();
GmailThread::getLabels()
GmailThread has labels, not GmailMessage. It returns an array of labels. Maybe use:
var labelsString = "";
var labelArray = []
for each (var label in labels)
{
labelArray.push(label.getName());
}
if (labelArray.length > 0)
{
labelsString = labelArray.join(',');
}
to insert into the row of the spreadsheet.
GmailLabel::getName()

Method is heavily used by the script

I am very new on using Google Apps Script and has a shallow knowledge on programming. What I am trying to do is copy the values of specific columns to a different Spreadsheet. Here's my code:
function myFunction() {
var ss = SpreadsheetApp.getActive();
var responses = ss.getSheetByName("Responses ID");//Where ID's of the spreadsheets are listed.
var consolidatedSheet = ss.getSheetByName("Consolidated");//Where the data should be pasted.
var responseColValues = responses.getRange(2,2, responses.getMaxRows() -1).getValues();
var responsesIds = [i for each (i in responseColValues)if (isNaN(i))];
var ssSelected = SpreadsheetApp.openById(responsesIds[0]);
var selectedSheets = ssSelected.getSheets();
for (i=0; i<3; i++){
var maxRows = selectedSheets[i].getLastRow()-1;
var x=2, y=2;
var lastRow = consolidatedSheet.getLastRow()+1;
for (j=0; j<maxRows; j++){
var eventID = selectedSheets[i].getRange(y,2).getValue();
var employeeName = selectedSheets[i].getRange(y,3).getValue();
var productionDate = selectedSheets[i].getRange(y,4).getValue();
var consolidatedSheetCell = consolidatedSheet.getRange(lastRow,1).setValue(eventID);
var consolidatedSheetCell = consolidatedSheet.getRange(lastRow,2).setValue(employeeName);
var consolidatedSheetCell = consolidatedSheet.getRange(lastRow,3).setValue(productionDate);
y++;
lastRow++;
}
}
}
However, I am experiencing this notification on the Execution hints (light bulb icon):
screenshot of the message. I am thinking that my code can be simplified. I am just not sure how to do it. Thank you in advance.
Every line with .getRange().getValue() and getRange.setValue() is a call to the file. Since you have these inside a for(){} loop, they are being called many times. Your goal is to limit these to as few as possible. Since you can read and write a range, you could do something similar to this:
function myFunction() {
var ss = SpreadsheetApp.getActive();
var responses = ss.getSheetByName("Responses ID");//Where ID's of the spreadsheets are listed.
var consolidatedSheet = ss.getSheetByName("Consolidated");//Where the data should be pasted.
var responseColValues = responses.getRange(2,2, responses.getMaxRows() -1).getValues();
var responsesIds = [i for each (i in responseColValues)if (isNaN(i))];
var ssSelected = SpreadsheetApp.openById(responsesIds[0]);
var selectedSheets = ssSelected.getSheets();
for (i=0; i<3; i++){
var maxRows = selectedSheets[i].getLastRow()-1;
var y=2;
var lastRow = consolidatedSheet.getLastRow()+1;
var copyValues = selectedSheets[i].getRange(y,2, maxRows, 4).getValues();
consolidatedSheet.getRange(lastRow,1, maxRows, 4).setValues(copyValues);
}
}