Running an IF script across multiple ranges - google-apps-script

I've put together a script that takes the values of 4 cells in a row ,A23:E23, and duplicates those values in another sheet if a specific (H3) cell in that row contains the text "Live".
The script needs to run daily, which I understand I can do with ease, but it also needs to work with every row below row 23 that contains values, with the reportData and ifd variables working respectively. i.e.
var reportData = reportSheet.getRange("A24...A25...A26:E24...E25...E26").getValues();
var lastRow = recordsSheet.getLastRow();
var ifd = reportSheet.getRange("H24...H25...H25").getValue();
The idea behind this script is to capture a daily snapshot of the values that are in Sheet1 as the values are constantly updated, but as cumulative figures. I need to capture a daily record of these cumulative figures.
function appendToRecords() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var reportSheet = ss.getSheetByName("Sheet1");
var recordsSheet = ss.getSheetByName("database")
var reportData = reportSheet.getRange("A23:E23").getValues();
var lastRow = recordsSheet.getLastRow();
var ifd = reportSheet.getRange("H23").getValue();
if (ifd == "Live"){
recordsSheet.getRange("A2:E2")
.setValues(reportData); }}
Can anyone suggest a way to do this?
Here's a sample sheet that the script works with: https://docs.google.com/spreadsheets/d/1FMlj_9l7Sm0QMKcFpbC4iExbATgPL0jIWoVrvV_Vcfw/edit?usp=sharing
Thanks!

You can easily log all "live" rows to your database like this:
function appendToRecords() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var reportSheet = ss.getSheetByName("Sheet1");
var recordsSheet = ss.getSheetByName("database")
var reportData = reportSheet.getRange("A8:H").getValues();
// Get only rows that are "Live"
// And only get the first five colums
var toWrite = reportData.filter(function(row) {
return row[7] === "Live";
}).map(function(row) {
return row.splice(0, 5);
});
if(!toWrite.length) {return;} // Return if nothing to write
recordsSheet
.getRange(recordsSheet.getLastRow() + 1, 1,
toWrite.length, toWrite[0].length)
.setValues(toWrite);
}

Related

How to copy a dynamic range or data to another sheet using google sheets script

I have created a named ranged called MW_DATA in my sheet which covers the range U12:AA105
Based on the data present there could be a variable number of rows of data in U12:AA105 every time I copy the data to a Games_Log sheet and clear the data in the cells.
I need to improve the code so the filteredData variable is a dynamic range of rows each time (e.g. it could be U12:AA12 or U12:AA75)
current code:
function SaveMWData() {
var dataSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Games_Log");
var dataRange = dataSheet.getDataRange();
var dataLocation = dataRange.getLastRow();
var mwData = sheet.getRange("MW_DATA");
mwData.copyTo(dataSheet.getRange(dataLocation + 1,1),{contentsOnly:true});
}
Above code keeps copying all rows, including blank rows into the Games_Log sheet
Code I can't figure out:
function SaveMWData() {
var unfilteredData = sheet.getRange("MW_DATA");
var filteredData = ??
filteredData.copyTo(dataSheet.getRange(dataLocation + 1,1),{contentsOnly:true});
}
Filtered data would only copy over the rows with data
I believe I got it working as follow:
function SaveMWData() {
var dataSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Games_Log");
var dataRange = dataSheet.getDataRange();
var dataLocation = dataRange.getLastRow();
var row = sheet.getRange("MW_ROW").getValue();
var column = sheet.getRange("MW_COLUMN").getValue();
var numrows = sheet.getRange("MW_NUMROWS").getValue();
var numcolumns = sheet.getRange("MW_NUMCOLUMNS").getValue();
var mwData = sheet.getRange(row,column,numrows,numcolumns);
mwData.copyTo(dataSheet.getRange(dataLocation + 1,1),{contentsOnly:true});
}

TypeError: rngOrgn.copyTo is not a function

I am new with javascript and I am trying to do a script that copy the value of the last raw of a sheet to the last raw of another sheet, if I donĀ“t set the number of columns to the range it only copy one value, however if I set the amount of columns it only returns that copy to is not a function, please if you can help me.
This is the code I am using:
function ORderReservation() {
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var hOrigen = spreadsheet.getSheetByName('Form responses 1');
var hDestino = spreadsheet.getSheetByName('TODAS AGENCIAS');
var filActiva = hOrigen.getLastRow();
var activeCell =hOrigen.getRange(filActiva,1)
var valor = activeCell.getValue();
if( valor>= 0)
var rngOrgn = hOrigen.getRange(filActiva,1,1,8).activate;
var detsin = hDestino.getLastRow()+1;
rngOrgn.copyTo(hDestino.getRange(hDestino.getLastRow()+1,1,1,8),SpreadsheetApp.CopyPasteType.PASTE_VALUES,false);
}

Add Timestamp if row is not empty

I have a script on a nightly trigger which does the following three things:
copies the contents of one spreadsheet (spreadsheet 1) to another (spreadsheet 2).
adds a timestamp column to column A each time the script is run.
deletes rows if there are certain values in column D.
The first time the script runs, everything works fine (i.e. when the new spreadsheet 2 is still blank). The subsequent times it runs it encounters issues.
With some research I have discovered that is because any blank rows in the source sheet (spreadsheet 1) are copied to the new spreadsheet (spreadsheet2) and a timestamp is placed in the blank rows. This leaves a bunch of rows that only have a timestamp. By the time the script gets to the part where it is supposed to delete rows based on values it gets thrown by these rows that only have a timestamp.
I am new to google script and was unable to find anything in the forum. Is there a way to modify the script so that the timestamp is only placed on rows where there is data?
var sourceSpreadsheetID = "spreadsheet1 ID";
var sourceWorksheetName = "BusinessDetails";
var targetSpreadsheetID = "spreadsheet2 ID";
var targetWorksheetName = "Sheet5";
function importBusinessDetailsData(){
var thisSpreadsheet = SpreadsheetApp.openById("spreadsheet1 ID");
var thisWorksheet = thisSpreadsheet.getSheetByName("BusinessDetails");
var thisData = thisWorksheet.getDataRange();
var toSpreadsheet = SpreadsheetApp.openById("spreadsheet2 ID");
var toWorksheet = toSpreadsheet.getSheetByName("Sheet5");
var toRange = toWorksheet.getRange(1,2, thisData.getNumRows(), thisData.getNumColumns())
toRange.setValues(thisData.getValues());
setTimeStamp()
main()
removeThenSetNewVals()
}
function setTimeStamp() {
SpreadsheetApp.getActive().getSheetByName('Sheet5')
.getRange('A2:A').setValue(new Date())
};
function main() {
var startTime = new Date().getTime();
var deleteSelectedRows = removeThenSetNewVals();
var runTime = (new Date().getTime() - startTime) / 1000;
Logger.log("Runtime is: " + runTime + " seconds");
};
function removeThenSetNewVals(){
var sheet = SpreadsheetApp.getActive().getSheetByName('Sheet5');
var range = sheet.getDataRange();
var pattern = new RegExp("value1|value2|value3");
var columnToSearch = 3;
var newRangeVals = range.getValues().filter(r => r[0] && !pattern.exec(r[columnToSearch]))
range.clearContent();
var numRows = newRangeVals.length;
var newRange = sheet.getRange(1,1, numRows, newRangeVals[0].length).setValues(newRangeVals);
var maxRows = sheet.getMaxRows();
}
As far as I understand, you only want to write entries to the new sheet which fit a particular condition. Basically, you want to filter the records before you write them, therefore consider the following:
var thisData = thisWorksheet.getDataRange();
var rowsWithData = thisData.filter( row => row[3] )
This states that only rows which contain truthy data will be considered, but feel free to fit the condition according to your needs.
References
filter()
truthy

Move Rows En Masse Contingent on Value in One Column

I have a script setup that moves all the records in a sheet into another sheet. However, I would like to add functionality to only move records that have the value "Approved" in a specific column (column I for my current situation). I've seen some other questions/answers to move individual rows based on values, but I haven't figured out how to leverage these scripts to run across a full spreadsheet. My guess is I can use a for loop but how?
Current script:
function MoveRecords(){
//Original Sheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Example Input")
//Calculate # of Rows Ignoring Blank Array Values
var Rows = ss.getRange("A2:A").getValues();
var NumRows = Rows.filter(String).length;
/*Add a For Loop here to only get the rows with Approved in Column I?*/
//Parsed Data to Move
var rangeValues1 = sheet.getRange(2,1,NumRows,1).getValue();
var rangeValues2 = sheet.getRange(2,2,NumRows,5).getValues();
//Destination of Parsed Data
var DestinationSS = SpreadsheetApp.openById('ID');
var DestinationSheet = DestinationSS.getSheetByName('Approved');
var DestinationLastRow = DestinationSheet.getLastRow()+1;
//Move the Data
DestinationSheet.getRange(DestinationLastRow,3,NumRows,1).setValue(rangeValues1);
DestinationSheet.getRange(DestinationLastRow,5,NumRows,5).setValues(rangeValues2);
};
Any help is greatly appreciated!
You can get all values, filter every row for Approved then write those rows into destination sheet.
function MoveRecords() {
//Original Sheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Example Input');
var values = sheet.getDataRange().getValues();
/*Add a For Loop here to only get the rows with Approved in Column I?*/
// col I = index 8
var res = values.filter(function(row) {
return row[8] == 'Approved';
});
//Parse Data to Move
var rangeValues1 = res.map(function(row) {
return [row[0]];
});
var rangeValues2 = res.map(function(row) {
row.shift();
while (row.length > 5) row.pop();
return row;
});
//Destination
var DestinationSS = SpreadsheetApp.openById('ID');
var DestinationSheet = DestinationSS.getSheetByName('Approved');
var DestinationLastRow = DestinationSheet.getLastRow() + 1;
//Move the Data
DestinationSheet.getRange(DestinationLastRow, 3, rangeValues1.length, 1).setValues(rangeValues1);
DestinationSheet.getRange(DestinationLastRow, 5, rangeValues2.length, 5).setValues(rangeValues2);
}

move a row in google spreadsheet based on todays date

I'm trying to move a row of data from one sheet to another in the same spreadsheet based on a value of today's date.
In column "A", I have a date. I want to move the row if the date entered in column "A" is older than today's date. (it's a flight schedule for aircraft and I want to move flights that have already occured onto a sheet called "Past Flights".) The name of the active sheet is "Flight Schedule".
After the row is moved, I want it to delete off the "Flight Schedule" sheet. I know where to add scripts, but have no idea how to make this happen.
Here is what I have tried. I think on line "If (data.link >1..." data.link isn't the right one to use. But I can't find something for indicating older than todays date.
function approveRequests() {
var ss = SpreadsheetApp.getActiveSpreadsheet()
sheet = ss.getActiveSheet(),
sheetName = sheet.getName(),
data = sheet.getDataRange().getValues();
if (sheetName == "Flight Shedule") {
var range = sheet.getActiveRange(),
startRow = range.getRowIndex(),
numRows = range.getNumRows(),
numCols = range.getNumColumns()
if (numCols == 9) {
if (data.length > 1) {
var values = range.getValues(),
nextSheet = ss.getSheetByName("Past Flight"),
lastRow = nextSheet.getLastRow();
nextSheet.getRange(lastRow+1,1,numRows,3).setValues(values);
sheet.deleteRows(startRow,numRows);
}
}
}
}
Any help would be huge!
Thanks!
Ok, I will go in with some general tips based on your current code first.
In your function you do a sheet = ss.getActiveSheet() which is redundant because you already have SpreadsheetApp.getActiveSpreadsheet().Also I would recommend to avoid this
var ss = SpreadsheetApp.getActiveSpreadsheet()
sheet = ss.getActiveSheet(),
sheetName = sheet.getName(),
data = sheet.getDataRange().getValues();
in favour of this:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var sheetName = sheet.getName();
var data = sheet.getDataRange().getValues();
which is much more easy to read and change without making mistakes.
data.length has nothing to do with current date, it will simply be the length of the array. So if you select 1 row of data, it will be 1, if you select 2 rows it will be 2 etc. .getValues() will return an array where data[row][col]. What you are looking for is getting the value of the flight time, converting it into a date object (not a google specific thing, just general javascript). Then use var now = new Date() and compare the two.
I would also recommend to re-think your if statements. There are a lot of better ways to grab the row data than selecting the row manually and then running the function. You can save a lot of lines of code should you decide to actually make this run automatically, because as it is, it will run only when called manually.
This sample is working:
function approveRequests() {
// Initialising
var ss = SpreadsheetApp.getActiveSpreadsheet();
var scheduleSheet = ss.getSheetByName("Flight Shedule");
var pastSheet = ss.getSheetByName("Past Flight");
var lastColumn = scheduleSheet.getLastColumn();
// Check all values from your "Flight Schedule" sheet
for(var i = scheduleSheet.getLastRow(); i > 0; i--){
// Check if the value is a valid date
var dateCell = scheduleSheet.getRange(i, 1).getValue();
if(isValidDate(dateCell)){
var today = new Date();
var test = new Date(dateCell);
// If the value is a valid date and is a past date, we remove it from the sheet to paste on the other sheet
if(test < today){
var rangeToMove = scheduleSheet.getRange(i, 1, 1, scheduleSheet.getLastColumn()).getValues();
pastSheet.getRange(pastSheet.getLastRow() + 1, 1, 1, scheduleSheet.getLastColumn()).setValues(rangeToMove);
scheduleSheet.deleteRow(i);
}
}
}
}
// Check is a valid date
function isValidDate(value) {
var dateWrapper = new Date(value);
return !isNaN(dateWrapper.getDate());
}
So yes, It's not the optimized solution (cause of the use of several sheet.getRange() method), but it's working and allowing to have a clear code.