I am trying to create a google script that will scan through a specific column of one google sheet and check if any new additions are a duplicate. I have come up with the following, but it isn't working.
function hasDuplicates() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Customer and form Details");
var array = sheet.getRange('B2:B' + lastRow).getValues();
var valuesSoFar = [];
for (var i = 0; i < array.length; ++i) {
var value = array[i];
if (value in valuesSoFar) {
SpreadsheetApp.getUi().alert('Hello, world!');
}
else{
valuesSoFar.push(value);
}
}
}
As far as Im aware the above code creates an array called array and populates it with the specific range I am interested in. I then create a new, empty, array called valuesSoFar. The code then loops through the column and sequentially checks if that item has already been seen before, if so it gives you an alert. If not it adds it to the list of new items and keeps going.
It looks a bit like you are using the online documentation code.
But the following assignment is missing:
var lastRow = sheet.getLastRow();
or just replace lastRow with sheet.getLastRow()
Update:
I assume that the following solution should work if you actually have any duplicates in your column B:
function hasDuplicates() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Customer and form Details");
var array = sheet.getRange('B2:B' + sheet.getLastRow()).getValues();
var valuesSoFar = [];
for (var i = 0; i < array.length; ++i) {
var value = array[i][0];
if (value in valuesSoFar) {
SpreadsheetApp.getUi().alert('Hello, world!');
} else {
valuesSoFar.push(value);
}
}
}
If it isn't working yet, I am sorry.
As long as you can not provide any information on what kind of error you are running into, I will not look into this anymore.
Related
I am a very beginner, so I am sorry for asking a low-leveled question.
I want to drag out values on each merged cell (8 cells for each and listed down on a spreadsheet), and want to put them in a pull-down of google form.
I just tried to see values on the sheet but found out there was an error.
If someone know how to fix this, I am glad to hear that.
Error
TypeError: Cannot read property 'getRange' of undefined
updateFormList # Code.gs:13
function updateFormList() {
var formId = '---'
var sheetId = '---'
var sheetName = 'Sheet1'
var range = sheet.getRange("A3:A10");
var mergedRanges = range.getMergedRanges();
for (var i = 0; i < mergedRanges.length; i++) {
Logger.log(mergedRanges[i].getA1Notation());
Logger.log(mergedRanges[i].getDisplayValue());
}
}
To fix the error you have to assign a Class Sheet object to the variable named sheet.
function updateFormList() {
var formId = '---'
var sheetId = '---'
var sheetName = 'Sheet1'
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet(); // this works in scripts bounded to spreadsheet
var sheet = spreadsheet.getSheetByName(sheetName);
var range = sheet.getRange("A3:A10");
var mergedRanges = range.getMergedRanges();
for (var i = 0; i < mergedRanges.length; i++) {
Logger.log(mergedRanges[i].getA1Notation());
Logger.log(mergedRanges[i].getDisplayValue());
}
}
Regarding
I want to drag out values on each merged cell (8 cells for each and listed down on a spreadsheet), and want to put them in a pull-down of google form.
Merged cells might be helpful for data visualization, i.e. creating a report, but they might need more complex scripts and formulas. As a "very beginner" and when programming efficiency be important, whenever you can avoid having merged cells in your spreadsheets, specially if you will have to use formulas and scripts on their content.
Resources
https://developers.google.com/apps-script/guides/sheet
Try this:
function updateFormList() {
var formId = '---'
var sheetId = '---'
var sheetName = 'Sheet1'
const sheet = SpreadsheetApp.getActive().getSheetByName(sheetName);
var range = sheet.getRange("A3:A10");
var mergedRanges = range.getMergedRanges();
for (var i = 0; i < mergedRanges.length; i++) {
Logger.log(mergedRanges[i].getA1Notation());
Logger.log(mergedRanges[i].getDisplayValue());
}
}
I tried to write an Apps script for sending emails for those who forgot to update status report using google form.
It's my 1st script and I tried to fix it for almost 5 hours unsuccessfully.
Here is code:
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("summary");
var lastRow = sheet.getLastRow();
for ( var i=2; i<=lastRow; i++){
var currentEmail = sheet.getRange(i,11).getValue();
var templateText = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("emailbody").getRange(1,1).getValue();
var emailRecipient = sheet.getRange(i,2).getValue();
var messageBody = templateText.replace("{name}",emailRecipient);
var oldCheck = sheet.getRange(i,12).getValue();
if (oldCheck = "Old"){
MailApp.sendEmail(currentEmail,"Reminder: Fill the weekly status update form",messageBody);
}
else {
continue;
}
}
}
It sends only 1 email for the first "old" check.
Explanation:
Issue:
You want to compare the value of oldCheck with "Old" and not assign "Old" to oldCheck. You need to use == instead of =.
Improvements:
It is computationally expensive to use getValue inside a for loop. Instead use getValues before the for loop and work with the arrays. In this way, you eliminate reduntant API calls that make your script heavy especially when i increases.
Solution:
function sendEmails() {
var spreadsheet = SpreadsheetApp.getActive();
var sheet = spreadsheet.getSheetByName("summary");
var data = sheet.getDataRange().getValues();
var templateText = spreadsheet.getSheetByName("emailbody").getRange(1,1).getValue();
for (var i=1; i<data.length; i++){
var currentEmail = data[i][12];
var emailRecipient = data[i][3];
var messageBody = templateText.replace("{name}",emailRecipient);
var oldCheck = data[i][13];
// be careful! == instead of =
if (oldCheck == "Old"){
MailApp.sendEmail(currentEmail,"Reminder: Fill the weekly status update form",messageBody);
}
else {
continue;
}
}
}
I'm having trouble matching a string in an array. Column B2:Lastrow is defined as array which is "ID". I am trying to paste only unique entries to google sheet which aren't available in Column B2:Lastrow. Issue is..when I run the code it allows duplicates in the google sheet as well.
I was using it through count formula on the sheet but that leads to maximum code runtime error..hence I'm using the range as an array. Solves the error but not able to recognize if the string is unique.
// Code: List Gmail Label to Google Sheet and save attachment to GDrive
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet = spreadsheet.getSheetByName('Summary');
var label = GmailApp.getUserLabelByName("Caterpiller Account");
var threads = label.getThreads();
function getEmails() {
for (var i = 0; i < threads.length; i++) {
var row = sheet.getLastRow() + 1;
var message = threads[i].getMessages()[0];
var ID = message.getId();
var fulldata = sheet.getRange('B2:B' + row).getValues();
if (fulldata.indexOf(ID) == -1) {
var messages=threads[i].getMessages();
var listID=threads[i].getPermalink();
var listdate=threads[i].getLastMessageDate();
var message = threads[i].getMessages()[0];
var attachment = message.getAttachments();
var attachmentBlob = message.getAttachments()[0].copyBlob();
var folder = DriveApp.getFolderById("1ilsecZOexqTWGfAMu5xJDx1pKh3z1US-");
// EXTRACTOR CODE:
for (var m=0; m < messages.length; m++) {
sheet.getRange(row,1).setValue(messages[m].getSubject());
sheet.getRange(row,2).setValue(ID);
sheet.getRange(row,3).setValue(listdate); // Value - Date
for (var z=0; z<attachment.length; z++) {
var file = DriveApp.getFolderById("1ilsecZOexqTWGfAMu5xJDx1pKh3z1US-").createFile(attachmentBlob);
//Pending: Weblinkview (basically get permanent url of file) / Or self developed function that gets file through description (where description is email ID)
}
row++;
}
}
}
}
Expected: Unique entries & a faster Code runtime.
Actual: I'm crap & code time is still the same.
bool IsSame(string str,char arr[100])
{
if(str.lenght!=strlen(arr))return false;
for(int i=0;i<str.lenght;i++)
{
if(str[i]!=arr[i]) return false;
}
return true;
}
I have this script in Google Spreadsheet and it fetches all the rows marked "READY" just fine, then it sets the value in column "W"(23) to "SENT", and then I am trying to avoid fetching duplicates, by marking the column as "SENT" but then when I run the code again, it ignores the "SENT" that it just pasted? What is wrong here?
var ss = SpreadsheetApp.openById("12y85GmJ94s6k3213j2nGK8rFr0GOfd_Emfk8WHu_MUQ");
var stitchSheet = ss.getSheetByName("Sheet8");
var orderSheet = ss.getSheetByName("Sheet1");
var SENT = "SENT";
function getOrders() {
var range = orderSheet.getDataRange();
var orders = range.getValues();
for (var i = 1; i < orders.length; i++) {
var row = orders[i];
var status = row[1];
var order = row[4];
var name = row[5];
var system = row[22];
if(system != SENT){
if(status.toString() === 'READY'){
orderSheet.getRange(i,23).setValue(SENT);
stitchSheet.appendRow([order,name]);
}
}
}
}
Your code is fine, so there must be a logical error somewhere. I've noticed that you made var i in the for loop 1. I do not know if this is intentional or not, but the index of arrays pretty much always starts with 0 in most programming languages, which means that you'll start at row 2 of your sheet, not row 1.
Finding logical errors
To find logical errors you need to learn how to use the debugger console in the script editor.
Put breakpoints on the lines I mark with a star below:
var ss = SpreadsheetApp.openById("12y85GmJ94s6k3213j2nGK8rFr0GOfd_Emfk8WHu_MUQ");
var stitchSheet = ss.getSheetByName("Sheet8");
var orderSheet = ss.getSheetByName("Sheet1");
var SENT = "SENT";
function getOrders() {
var range = orderSheet.getDataRange();
* var orders = range.getValues();
for (var i = 1; i < orders.length; i++) {
* var row = orders[i];
var status = row[1];
var order = row[4];
var name = row[5];
* var system = row[22];
if(system != SENT){
if(status.toString() === 'READY'){
orderSheet.getRange(i,23).setValue(SENT);
stitchSheet.appendRow([order,name]);
}
}
}
}
Start the debugger and it will stop at the first breakpoint. Inspect what value range has. Expanding This should let you find orderSheet and SENT (since they are outside the function and should be in the scope). If not you've got a problem here.
Go to the next breakpoint and inspect orders, it should have an array of arrays now. You can inspect that you've got the right values, if not, skip forward to the next breakpoint and look at what row is.
I have 2 spreadsheet in my Drive. I want to pull data from a cell in 1 spreadsheet and copy it in another.
The spreadsheet "TestUsage" will sometimes have data in column A, but none is column B.
I would like so that when I open the spreadsheet, it would populate that empty cell in sheet "TestUsage" from sheet "TestParts".
Here is my code:
var ssTestUsage = SpreadsheetApp.getActiveSpreadsheet();
var sTestUsage = ssTestUsage.getActiveSheet();
var lastRowTestUsage = sTestUsage.getLastRow();
var rangeTestUsage = sTestUsage.getSheetValues(1, 1, lastRowTestUsage, 4);
var TESTPARTS_ID = "1NjaFo0Y_MR2uvwit1WuNeRfc7JCOyukaKZhuraWNmKo";
var ssTestParts = SpreadsheetApp.openById(TESTPARTS_ID);
var sTestParts = ssTestParts.getSheets()[0];
var lastRowTestParts = sTestParts.getLastRow();
var rangeTestParts = sTestParts.getSheetValues(1, 1, lastRowTestParts, 3);
function onOpen() {
for (i = 2; i < lastRowTestUsage; i++) {
if (rangeTestUsage[i][0] !== "" && rangeTestUsage[i][1] == "") {
for (j = 1; j < lastRowTestParts; j++) {
if (rangeTestUsage[i][0] == rangeTestParts[j][0]) {
Logger.log(rangeTestUsage[i][1]);
Logger.log(rangeTestParts[j][1]);
rangeTestUsage[i][1] = rangeTestParts[j][1];
break;
}
}
}
}
}
The problem with this is this doesn't do anything:
rangeTestUsage[i][1] = rangeTestParts[j][1];
I know there must be a method that can get data from one range to another.
Please let me know if I am totally incorrect or I am on the right path.
the statement
"this doesn't do anything:"
rangeTestUsage[i][1] = rangeTestParts[j][2];
is not really true... and not really false neither..., actually it does assign the value to rangeTestUsagei but you dont see it because it is not reflected in the spreadsheet.
Both values are taken from the Sheet using getValues so at that time they are both array elements.
What is missing is just writing back the array to the sheet using the symetrical statement setValues()
Give it a try and don't hesitate to come back if something goes wrong.
EDIT :
I didn't notice at first that you were using getSheetValues instead of getValues (simply because I never use this one)... the only difference is that getValues is a method of the range class while yours belongs to the sheet class; the syntax is similar in a way, just use
Sheet.getRange(row,col,width,height).getValues()
it takes one word more but has the advantage to have a direct equivalent to set values
Sheet.getRange(row,col,width,height).setValues()
Serge insas has a good explanation of why your code doesn't work and hints at the solution below.
I recommend you use an array to store the updated values of column B that you want then set the entire column at the end.
Modifying your code...
var ssTestUsage = SpreadsheetApp.getActiveSpreadsheet();
var sTestUsage = ssTestUsage.getActiveSheet();
var lastRowTestUsage = sTestUsage.getLastRow();
var rangeTestUsage = sTestUsage.getSheetValues(1, 1, lastRowTestUsage, 2);
var TESTPARTS_ID = "1NjaFo0Y_MR2uvwit1WuNeRfc7JCOyukaKZhuraWNmKo";
var ssTestParts = SpreadsheetApp.openById(TESTPARTS_ID);
var sTestParts = ssTestParts.getSheets()[0];
var lastRowTestParts = sTestParts.getLastRow();
var rangeTestParts = sTestParts.getSheetValues(1, 1, lastRowTestParts, 2);
var colB = [];
function onOpen() {
for (i = 2; i < lastRowTestUsage; i++) {
if (rangeTestUsage[i][0] !== "" && rangeTestUsage[i][1] == "") {
var matched = false;
for (j = 1; j < lastRowTestParts; j++) {
if (rangeTestUsage[i][0] == rangeTestParts[j][0]) {
//Logger.log(rangeTestUsage[i][1]);
//Logger.log(rangeTestParts[j][1]);
colB.push([rangeTestParts[j][1]]); // push the value we want into colB array
matched = true;
break;
}
}
if(!matched) // this is in case you don't have a match
colB.push([""]); // incase we don't have a matching part
} else {
colB.push([rangeTestUsage[i][0]]); // we already have a value we want so just add that to colB array
}
}
sTestUsage.getRange(2,2,lastRowTestUsage).setValues(colB); // update entire column b with values in colB array
}