Numbers of rows to process - javascript

I would like to make sure that an e-mail is not send twice. The script itself is working, however the Insertion of:
sheet.getRange(startRow + i, 6).setValue(EMAIL_SENT);
does not work, yet it adds a random value to row 40.
Could someone help me figure out the problem? Thanks a lot already in advance!
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getRange(1, 2);
var subject = range.getValues();
var range = sheet.getRange(1, 9);
var numRows = range.getValues();
var startRow = 4;
var dataRange = sheet.getRange(startRow, 1, numRows,9)
var data = dataRange.getValues();
var EMAIL_SENT = "EMAIL_SENT";
for (i in data) {
var row = data[i];
var emailAddress = row[0];
var message = row[8];
var emailSent = row[5];
if (emailSent != EMAIL_SENT) {
MailApp.sendEmail(emailAddress, subject, message,{noReply: true});
sheet.getRange(startRow + i, 6).setValue(EMAIL_SENT);
}
}
}

Short answer
Instead of using for(i in data){...} use for(var i = 0;i < data.lenght;i++) {...}
Explanation
for (variable in object) assigns a different property name on each iteration but what you need is the data index to be used to calculate the row index.
Reference
for..in

Related

I want to combine JavaScript Objects with the same variable name

Right now, If i run for loop
{“FirstName” : “Kim”}
{“LastName” : “hana”}
{“Phone” : “010-1234-5648”}
{“Email” : “abc#gmail.com”}
It comes out like this.
But the result I want is
{“FirstName” : “Kim”, “LastName” : “hana”, “Phone” : “010-1234-5648”, “Email” : “abc#gmail.com”}
I want to make it come out like this.
What should I do?
This is my code that I just wrote.
function testRun(){
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var LastRow = ss.getLastRow();
var LastCol = ss.getLastColumn();
var arr = [];
for(var i = 1; i<=LastCol; i ++){
var fieldName = ss.getRange(1,i).getValue();
arr.push(fieldName);
}
//arr = [FirstName, LastName, Phone, Email]
for(var i =2;i<=LastRow;i++){
for(var j=1;j<=LastCol;j++){
var payload = Utilities.jsonStringify({
[arr[j-1]] : ss.getRange(i,j).getValue()}
);
}
}
}
Modification points:
In your showing script, it seems that payload is not used.
When getValue() is used in a loop, the process cost becomes high. Ref
When these points are reflected in a sample script for achieving your goal, it becomes as follows.
Sample script:
When your showing script is modified, how about the following modification?
function testRun() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var LastRow = ss.getLastRow();
var LastCol = ss.getLastColumn();
var [header, ...values] = ss.getRange(1, 1, LastRow, LastCol).getValues();
var arr = [];
for (var i = 0; i < LastRow - 1; i++) {
var temp = {};
for (var j = 0; j < LastCol; j++) {
temp[header[j]] = values[i][j];
}
arr.push(temp);
}
console.log(JSON.stringify(arr))
}
When this script is run, arr is [{"FirstName":"Kim","LastName":"hana","Phone":"010-1234-5648","Email":"abc#gmail.com"}].
As another apporach, I thought that you might be able to also use the following sample script.
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var [header, ...values] = ss.getRange(1, 1, ss.getLastRow(), ss.getLastColumn()).getValues();
var arr = values.map(r => header.reduce((o, h, j) => (o[h] = r[j], o), {}));
console.log(JSON.stringify(arr))
Your code creates separate objects in each iteration. Create an empty object for every Person, then add the properties you need.
This should look something like this:
for(var i=2; i<=LastRow; i++){
var payload = {}
for(var j=1; j<=LastCol; j++){
payload[arr[j-1]] = ss.getRange(i,j).getValue()};
}
}

copy rows to target sheet if col 5 is not blank

Here is the code I have worked on- I have tried many different combinations and none of them are giving me the desired results- Can you please explain why my code is incorrect?
the code is iterating the the rows looking for rows larger than 0- if so, copy the row to the target sheet- However I am getting the wrong rows copied over?
function try2() {
var sheet1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet1');
var sheet2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Final');
var lastrow = sheet2.getLastRow()+1;
var target = sheet2.getRange(lastrow,1,1,5);
var data = sheet1.getRange('E1:E500').getValues();
for(var i=1; i< data.length; i++) {
Logger.log(i)
if (data[i] > 0) {
Logger.log(data[i])
sheet1.getRange(i, 1, 1, 5).copyTo(target);
}
}
}
I updated the code to have the lastrow & target variables in the for loop with still undesired results.
function try2() {
var sheet1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet1');
var sheet2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Final');
var data = sheet1.getRange('E1:E500').getValues();
for(var i=1; i< data.length; i++) {
var lastrow = sheet2.getLastRow()+1;
var target = sheet2.getRange(lastrow,1,1,5);
//Logger.log(i)
if (data[i] !== "") {
Logger.log(data[i])
sheet1.getRange(i, 1, 1, 5).copyTo(target);
}
}
}
Requirement:
Copy data from one sheet to the next free row of another sheet.
Solution:
function try2() {
var sheet1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet1');
var sheet2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Final');
var targetLastRow = sheet2.getLastRow() + 1;
var dataLastRow = sheet1.getLastRow();
var dataRange = sheet1.getRange(1,5,dataLastRow);
var data = dataRange.getValues();
for(var i = 0; i < data.length; i++) {
if (data[i]) {
sheet1.getRange(i+1, 1, 1, 5).copyTo(sheet2.getRange(targetLastRow+i,1));
}
}
}
Explanation:
This script will loop through all of the rows in column E on your first sheet, and copy any that aren't blank across to your sheet "Final". By using dataLastRow to get the data. You save time over defining a set range E1:E500, the script will now only get the necessary amount of rows to run the copy whereas before it was running the for loop 500 times no matter what.
The data is copied to targetLastRow+i, which is the next available row of sheet "Final", incremented by 1 every time the loop completes.
Code that worked altering #ross code- Thanks
function try3() {
var sheet1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet1');
var sheet2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Final');
var targetLastRow = sheet2.getLastRow() + 1;
var dataLastRow = sheet1.getLastRow();
var dataRange = sheet1.getRange(1,5,dataLastRow);
var data = dataRange.getValues();
for(var i = 0; i < data.length; i++) {
Logger.log(data[i])
if (data[i] > 0) {
Logger.log(data[i])
sheet1.getRange(i+1, 1, 1, 5).copyTo(sheet2.getRange(targetLastRow+i,1));
}
}
}

Google Script to scan gmail inbox and write to spreadsheet, too slow

Thanks in advance for your help.
I discovered Google Script recently and have been trying to write a script that scans the most recent 500 emails in my inbox a few times a day, reviews the content of each email thread, and then compares the sender of each email, with email addresses in a spreadsheet. If a sender matches an email address in the spreadsheet, the script should enter "yes". Here is the code I have been able to come up with below. The problem I am having is that the code is very slow, and after it gets through about 100 rows of data, it times out.
I am wondering if an expert has an idea on where I am going wrong? I am sure my code is very flawed. However, I'm unable to figure out how to improve it.
function getMail(){
var thread = GmailApp.getInboxThreads(0,500);
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2;
var numRows = 300; // Number of rows to process
var dataRange = sheet.getRange(startRow, 1, numRows, 10); //
var data = dataRange.getValues();
var target = "Sales Email"
for (var b = 0; b < data.length; ++b){
var row = data[b];
var leadEmail = row[4];
for (var i = 0; i < thread.length; ++i){
var message = thread[i].getMessages();
for(var c = 0; c < message.length; ++c){
var currentMessage = message[c];
var subject = currentMessage.getSubject();
if(subject.indexOf(target) !== -1) {
var sender = currentMessage.getFrom().replace(/^.+<([^>]+)>$/, "$1");
if(sender == leadEmail){
sheet.getRange(startRow + b, 7).setValue("yes");
SpreadsheetApp.flush();
break;
}
}
}
}
}
}
I managed to make the code a lot faster. It isn't necessary to fetch all messages from all threads over and over again for each row. Just fetch them once and write the sender into an array.
function getMail(){
var senders = [],
threads = GmailApp.getInboxThreads(0,500),
target = "Sales Email";
for (var i = 0; i < threads.length; ++i) {
var messages = threads[i].getMessages();
for(var j = 0; j < messages.length; j++) {
var currentMessage = messages[j],
subject = currentMessage.getSubject(),
sender = currentMessage.getFrom().replace(/^.+<([^>]+)>$/, "$1");
if(subject.indexOf(target) !== -1) senders[sender] = true;
}
}
var sheet = SpreadsheetApp.getActiveSheet(),
startRow = 2,
numRows = 300,
dataRange = sheet.getRange(startRow, 1, numRows, 10),
data = dataRange.getValues();
for (var b = 0; b < data.length; ++b) {
var row = data[b],
leadEmail = row[4];
if(senders[leadEmail]) {
sheet.getRange(startRow + b, 7).setValue("yes");
}
}
}

Transpose columns into rows through loop

I'm trying to transpose (copy column content into a row) a range from one sheet to another. Yet the catch is that each row has a different number of columns populated, and I don't want to have blank columns copied over into the output sheet.
So I was trying to do the following:
Go to 'import manipulation' tab
row by row (in a loop), check what the last POPULATED column is
Then col by col (second loop), copy each cell's value then paste it onto "Transpose" sheet in the first available row
Keep doing this until the last Populated column was copied over, and then move onto the next row
Repeat
I've ran the debugger and nothing comes up, however when I run the function it doesn't paste anything into the "Test" sheet. Any suggestions?
function transpose(sh) {
var sh = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Import Manipulation");
var lastrow = sh.getLastRow();
var numrows = lastrow;
for(var i= 1; i<= numrows; i++) {
Logger.log(i);
var rowrange = sh.getRange(i, 50);
Logger.log(rowrange);
var lastcol = rowrange.getValues().length;
for(var j=5; j<= lastcol; j++) {
var colrange = sh.getRange(i,j);
var copycell = colrange.getValue();
var pastesheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Test");
var pasterow = pastesheet.getLastRow();
Logger.log(pasterow);
var pastecell = pastesheet.getRange(pasterow + 1, 1);
Logger.log(pastecell);
var doit = pastecell.setValue(copycell);
doit(pastecell);
}
}
}
I was able to do it so that it transposes, and it's working (albeit probably not the most efficient).... appreciate suggestions for how to make it more efficient!
function transpose(sh) {
var sh = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Import Manipulation");
var lastrow = sh.getLastRow();
var numrows = lastrow;
var lastcol = sh.getLastColumn();
for(var i= 1; i<= numrows; i++) {
Logger.log(i);
var rowrange = sh.getRange(i,1,1,lastcol);
Logger.log(rowrange);
for(var j=5; j<= lastcol; j++) {
var colrange = sh.getRange(i,j);
var copycell = colrange.getValue();
var pastesheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Transpose");
var pasterow = pastesheet.getLastRow();
Logger.log(pasterow);
var pastecell = pastesheet.getRange(pasterow + 1, 1);
Logger.log(pastecell);
pastecell.setValue(copycell);
}
}
}
This line of code:
var rowrange = sh.getRange(i, 50);
Is only getting one cell. On the first loop, it gets the cell in row 1 column 50.
The variable lastcol in this line:
var lastcol = rowrange.getValues().length;
will always be 1. getValues() gets a 2D array and in this case it will be [[cellValue]]
I created some new code:
function transpose(sh) {
var arrayThisRow,cellValue,i,j,lastCol,lastrow,numrows,pastesheet,
rowrange,rowValues,sh;
sh = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Import Manipulation");
pastesheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Test");
lastrow = sh.getLastRow();
lastCol = sh.getLastColumn();
Logger.log('lastCol: ' + lastCol);
numrows = lastrow;
arrayThisRow = [];
for(i=1; i<= numrows; i++) {
//Logger.log(i);
rowrange = sh.getRange(i,1,1,lastCol);
//Logger.log(rowrange);
rowValues = rowrange.getValues();//
rowValues = rowValues[0];//There is only 1 inner array
for(j=0; j <= lastCol; j++) {
cellValue = rowValues[j];
if (cellValue) {
arrayThisRow.push(cellValue);
} else {
break;//Stop pushing values into the array as soon as a blank cell is found
}
}
}
Logger.log('arrayThisRow: ' + arrayThisRow)
if (arrayThisRow.length > 0) {
pastesheet.appendRow(arrayThisRow)
}
}

Google Spreadsheets script to delete any rows where a string is found

I need to loop through all rows/columns in a sheet and remove rows contain certain words. Ideally, I would search through the sheet using a regular expression, but just finding a string would help get me moving. I'm seeing a lot of posts on Stack Overflow about finding and deleting empty rows, but can't find anything about searching an entire sheet and deleting a row if found.
This is what I have so far:
/* Delete rows */
function deleteRows() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var rows = sheet.getDataRange();
var numRows = rows.getNumRows();
var values = rows.getValues();
var deleted = 0; // Counter (don't need if we loop backwards)
var regExp = new RegExp('word');
for (var row = 0; row < values.length; row++) {
var regExpMatch = values[row][1].match(regExp);
if (regExpMatch.length > 0) {
sheet.deleteRow(row + 1 - deleted);
deleted++;
}
}
SpreadsheetApp.flush();
};
However this only searches Column B, and it throws an error "TypeError: Cannot read property 'length' from null" even though "word" exists in Column B in my spreadsheet. And if I do a simpler version like:
/* Delete rows */
function deleteRows() {
var sheet = SpreadsheetApp.getActiveSheet();
var rows = sheet.getDataRange();
var numRows = rows.getNumRows();
var values = rows.getValues();
var deleted = 0; // Counter (don't need if we loop backwards)
for (var row = 0; row < values.length; row++) {
if (values[row][1].search("WordThatExistsInOneRow")) {
sheet.deleteRow(row);
deleted++;
}
}
SpreadsheetApp.flush();
};
It starts deleting every row, even if "WordThatExistsInOneRow" only shows up in 1 row.
You have not wrote your loop logic correctly, you need to loop over each row then each column in that row and then assign the row index for deletion which must be performed in revere order. Try this:
/* Delete rows */
function deleteRows() {
var sheet = SpreadsheetApp.getActiveSheet();
var rows = sheet.getDataRange();
var numRows = rows.getNumRows();
var values = rows.getValues();
var toDelete = [];
for (var row = 0; row < values.length; row++) {
for(var column = 0;column<values[row].length;column++){
if (values[row][column].indexOf("WordThatExistsInOneRow") > -1){
toDelete.push(row);
}
}
}
for(var deleteRow = toDelete.length-1; deleteRow >= 0;deleteRow--){
sheet.deleteRow(toDelete[deleteRow]+1);
}
SpreadsheetApp.flush();
};

Categories

Resources