I have spreadsheet1 with all the details as in this image(Spreadsheet1), there are columns with startDate and endDate with some dates. Now i have a different spreadsheet2 like in this image (spreadsheet2) with header row of all the dates in the year (from 01/01/2021 to 31/12/2021). Now startDate and endDate from spreadsheet1 should match the header in spreadsheet2 and put the values of the column Type from spreadsheet1 to the respective cells in spreadsheet2 (like it is present in spreadsheet2 image for reference). Below is the code i'm working with but i'm not reaching my goal. Please help me i'm new to coding world. Thank you.
function myFunction() {
let ss = SpreadsheetApp.getActiveSpreadsheet();
let sheet = ss.getActiveSheet();
let last_row = sheet.getLastRow();
let data = sheet.getRange("A2:E"+last_row).getValues();
let start_date = [];
let end_date = [];
let dates_between = [];
let id = [];
let name = [];
let message = [];
let dd = SpreadsheetApp.openById('1z5WB1sACp1zvgfyXDbAmYxklSZOMIC8kNi_3Yci-PkM');
let dsheet = dd.getActiveSheet();
let dlast_row = dsheet.getLastRow();
let ddata = dsheet.getRange('C2:NC'+dlast_row).getValues();
let did = dsheet.getRange('A2:A'+last_row);
for(let i = 0; i<data.length;i++){
// let id = data[i][0];
id.push(data[i][0]);
name.push(data[i][1]);
start_date.push(data[i][2]);
end_date.push(data[i][3]);
message.push(data[i][4]);
dates_between.push(DATES_BETWEEN(start_date[i], end_date[i]));
}
did.setValue(id);
}
function DATES_BETWEEN(dateFrom, dateTo) {
var t = dateFrom.getTime(),
tMax = dateTo.getTime(),
values = [];
while (t <= tMax) {
values.push(new Date(t));
t += 24000 * 3600;
}
return values;
}
If you're able to put your 'types' on the row at start date and at end date you can fill the gap in-between with Array.fill() method.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fill
All you need is to get the row as an array and to put it back on the sheet. You don't even need to calculate dates in the gap. You just fill all these empty elements between filled start and end cells.
Here is your row/array: ['','','x','','','x','','']
Start cell is array.indexOf('x')
End cell is array.lastIndexOf('x')
To fill the gap with 'x' strings use array.fill('x', start, end)
You will get: ['','','x','x','x','x','','']
Below is my solution that doesn't use Dates. If your dates have the same format on both sheets and if your destination sheet always has the dates of the rows of your source sheet you can consider them as strings, and use them as keys of an object (a map in my case):
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var src_sheet = ss.getSheetByName('Sheet1');
var dest_sheet = ss.getSheetByName('Sheet2');
// get dates from first row of destination sheet
var dates = dest_sheet.getDataRange().getDisplayValues()[0].slice(2);
// get rows (without first row) from source sheet
var rows = src_sheet.getDataRange().getDisplayValues().slice(1);
// loop through the rows and get the table
var table = rows.map(row => {
// get variables from the row
var [id, name, type, start, end] = row.slice(0, 5);
// create empty Map with dates-keys (date1:'', date2:'', ...)
var dates_map = new Map(dates.map(date => [date, '']));
// assign 'type' to key['start date'] and to key['end date']
dates_map.set(start, type).set(end, type);
// create array (row) from values of the Map
var row_array = Array.from(dates_map.values());
// fill empty elements of the array between first and last 'type'
row_array.fill(type, row_array.indexOf(type), row_array.lastIndexOf(type));
// return row
return [id, name, ...row_array];
});
// set the table on the destination sheet
dest_sheet.getRange(2, 1, table.length, table[0].length).setValues(table);
}
The same code without comments:
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var src_sheet = ss.getSheetByName('Sheet1');
var dest_sheet = ss.getSheetByName('Sheet2');
var dates = dest_sheet.getDataRange().getDisplayValues()[0].slice(2);
var rows = src_sheet.getDataRange().getDisplayValues().slice(1);
var table = rows.map(row => {
var [id, name, type, start, end] = row;
var dates_map = new Map(dates.map(date => [date,'']));
dates_map.set(start, type).set(end, type);
var row_array = Array.from(dates_map.values());
row_array.fill(type, row_array.indexOf(type), row_array.lastIndexOf(type));
return [id, name, ...row_array];
});
dest_sheet.getRange(2, 1, table.length, table[0].length).setValues(table);
}
Just in case, this is a destructuring assignment:
var [id, name, type, start, end] = row;
It means:
var id = row[0];
var name = row[1];
var type = row[2];
var start = row[3];
var end = row[4];
Here is the link to my dummy spreadsheet.
Related
I need to copy data from a selected range (Y5:Z198) to cell (Y206) but somehow I can only make it to appendRow and paste only on column A. Can someone help me, please?
function CopyData(CopyData) {
var ss = SpreadsheetApp.getActive();
var sh1 = ss.getSheetByName("CAPA");
var sh2 = ss.getSheetByName("CAPA");
var rg1 = sh1.getRange("Y5:Z198");
var vA = rg1.getValues();
for (var i = 0; i < vA.length; i++) {
if (vA[i][1]) {
sh2.appendRow(vA[i]);
}
}
}
Try this code to copy the data
function CopyData(CopyData) {
const dstRow = 206;
let ss = SpreadsheetApp.getActive(),
sheet = ss.getSheetByName('CAPA'),
srcRange = sheet.getRange('Y5:Z198'),
srcValues = srcRange.getValues(),
filtered = srcValues.filter(item => item[1]); // filter the data being copied
// Define the range to insert
// 'Y'+dstRow -> Y206
// filtered.length -> the number of rows in the filtered array of data
// ':Z'+(dstRow-1+filtered.length) -> bottom right cell
sheet.getRange('Y'+dstRow+':Z'+(dstRow-1+filtered.length)).setValues(filtered);
}
I want to create a new worksheet each time I have a new user details in column 1 of my USERS sheet. Here is the code I have so far:
// Get the data from the sheet called CreateSheets
var sheetNames = SpreadsheetApp.getActive().getSheetByName("USERS").getDataRange().getValues();
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("USERS");
var data = ss.getDataRange().getValues();
var lr = ss.getLastRow();
var dataRange = ss.getRange(1, 1, lr, 1);
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (var i = 0; i < data.length; ++i) {
var row = data[i];
// For each row in the sheet, insert a new sheet and rename it.
sheetNames.forEach(function(row) {
var sheetName = data;
var sheet = SpreadsheetApp.getActive().insertSheet();
sheet.setName(sheetName);
});
}}
The code works but it is combining the data in the cells in column 1 into the name of the new spreadsheet. Thanks
function myfunc() {
const ss = SpreadsheetApp.getActive();
const ush = ss.getSheetByName("USERS");
const names = ush.getRange(1, 1, ush.getLastRow(), 1).getValues().flat();
const enames = ss.getSheets().map(s => s.getName());
names.forEach(n => {
if (~e.names.indexOf(n)) {
ss.insertSheet().setName(n);
enames.push(n); //add name to array to avoid duplicate names in column
}
});
}
Updated to account for existing sheet names and potential duplicate names in column 1.
I think this should do what you want. You should probably build in some sort of check to ensure the sheet doesn't already exist.
function makeSheetHappen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var wsUser = ss.getSheetByName("USERS");//the sheet with users
//this gets all values in column 1 to end of spreadsheet (it might include blanks)
//flat function avoids having to pull 2-dim array (h/t COOPER!)
var sheetNames = wsUser.getRange(1, 1, wsUser.getLastRow(), 1).getValues().flat();
//mapping function to get an array of the spreadsheet's sheet names.
var theExistingNames = ss.getSheets().map(function (aSheet) {
return aSheet.getName();
});
//loops through the sheetNames and ensures not blank and not currently existing.
sheetNames.forEach(function (aName) {
if (aName != '' && !theExistingNames.includes(aName)) {
var newSheet = ss.insertSheet();
newSheet.setName(aName);
theExistingNames.push(aName); //add name to array to avoid duplicate names in column
}
});
}
Link of My sheet is :
https://docs.google.com/spreadsheets/d/1czJbRU5ELNft1IfGq1cABGe30j8BWjnffVCEa8A_AeY/edit?usp=sharing
I am trying to move data if N is equal to today. I have set the trigger. This script runs on time driven between 8 PM to 9 PM. It copies the data in Row 8 when column K onwards there is noting mentioned. In the current Payment Approval Sheet, while running the script it copies the data in 1500th row.
The script I am using is as below:
function copyrange() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Complete Invoice Sheet'); //source sheet
var testrange = sheet.getRange('N:N');
var testvalue = (testrange.setNumberFormat("#").getValues());
var ds = ss.getSheetByName('Payment Approval Sheet'); //destination sheet
var data = [];
var j =[];
var dt = new Date();
var today = Utilities.formatDate(new Date(), 'GMT-0', 'dd/MM/yyyy')
//Condition to check in N:N, if true, copy the same row to data array
for (i=0;i<testvalue.length;i++) {
if (testvalue[i] == today) {
data.push.apply(data,sheet.getRange(i+1,1,1,13).getValues());
//Copy matched ROW numbers to j
j.push(i);
}
}
//Copy data array to destination sheet
ds.getRange(ds.getLastRow()+1,1,data.length,data[0].length).setValues(data);
}
Issue:
Your current solution considers the last row of your destination
sheet Payment Approval Sheet. However, in that sheet, checkboxes
are populated in column N until the bottom of the sheet. Therefore,
getLastRow() returns the row at the bottom of column N which is not
what you want.
Explanation:
Instead of using getLastRow(), calculate the number of elements after cell A7 by using the filter() operation and then use this as a starting point when you copy & paste the data to the destination sheet:
var start_row=ds.getRange('A8:A').getValues().filter(String).length +7; //calculate max row
ds.getRange(start_row+1,1,data.length,data[0].length).setValues(data);
Solution:
function copyrange() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Complete Invoice Sheet'); //source sheet
var testrange = sheet.getRange('K:K');
var testvalue = (testrange.setNumberFormat("#").getValues());
Logger.log(testvalue);
var ds = ss.getSheetByName('Payment Approval Sheet'); //destination sheet
var data = [];
var j =[];
var dt = new Date();
var today = Utilities.formatDate(new Date(), 'GMT-0', 'dd/MM/yyyy')
//Condition to check in N:N, if true, copy the same row to data array
for (i=0;i<testvalue.length;i++) {
if (testvalue[i] == today) {
data.push.apply(data,sheet.getRange(i+1,1,1,13).getValues());
//Copy matched ROW numbers to j
j.push(i);
}
}
//Copy data array to destination sheet
var start_row=ds.getRange('A8:A').getValues().filter(String).length +7; //calculate max row
ds.getRange(start_row+1,1,data.length,data[0].length).setValues(data);
}
This script fetches the data from the sheet and insert it into a new sheet. I want the second function to insert into the third row each time.
I want the result to be -
Timestamp | Impressions | CTR
function AggregateData() {
Impressions();
CTR();
}
function Impressions() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Metrics");
var source = sheet.getRange("G16:H16");
var values = source.getValues();
var sheet = ss.getSheetByName("Aggregate");
values[0][0] = new Date();
sheet.appendRow(values[0]);
};
function CTR() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Metrics");
var source = sheet.getRange("F16:G16");
var values = source.getValues();
var sheet = ss.getSheetByName("Aggregate");
values[0][0] = new Date();
sheet.appendRow(values[0]);
};
This code appends the second function in the second column itself below the result of the first function.
This code will copy your data to a new sheet in the order you want. However, I have reduced it to one function. The reason your code puts the new data in a new row is this line:
Sheet.appendRow(data)
puts the data you supply to a new row which is empty. That is also the reason why i have combined the two functions into one.
function AggregateData() {
Impressions();
}
function Impressions() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Metrics");
var source = sheet.getRange("F16:H16");
var values = source.getValues();
var pasteValues = [] // create new array which will hold the data you need to be pasted into the aggregate Sheet
pasteValues[0] = [] // Adding a second dimesion to the array
var sheet = ss.getSheetByName("Aggregate");
// below 3 lines does the switch of data and adds the time stamp
pasteValues[0][0] = new Date();
pasteValues[0][1] = values[0][2] //Copy the col h (impressions value) value into the new array
pasteValues[0][2] = values[0][1] //Copy the col G (impressions value) value into the new array
sheet.appendRow(pasteValues[0]); //Append the new array into the sheet
};
function checkReminder() {
// get the spreadsheet object
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
// set the first sheet as active
SpreadsheetApp.setActiveSheet(spreadsheet.getSheets()[0]);
// fetch this sheet
var sheet = spreadsheet.getActiveSheet();
// figure out what the last row is
var lastRow = sheet.getLastRow();
// the rows are indexed starting at 1, and the first row
// is the headers, so start with row 2
var startRow = 2;
// grab column 10 (the 'date end' column)
var range = sheet.getRange(2,10,lastRow-startRow+1,1 );
var numRows = range.getNumRows();
var date_end_values = range.getValues();
// Now, grab the Event name data
range = sheet.getRange(2, 5, lastRow-startRow+1, 1);
var reminder_info_values = range.getValues();
var warning_count = 0;
var msg = "Send out a follow-up email asking how the event was!";
}
//Get today's date
var todaysDate = new Date();
var numRows = numRows
// Loop over the days left values
for (var i = 0; i <= numRows - 1; i++) {
var date_end = date_end_values[i][0];
//call setHours to take the time out of the comparison
if(date_end == todaysDate.setHours(0,0,0,0)) {
MailApp.sendEmail("max#xpogo.com",
"Reminder Spreadsheet Message", msg);
}
What I'm trying to do is have gmail send me a reminder when a certain column in my data set is equal to the present date. Im new to coding and am running into trouble. Please help?
I added the following after your variables were set, to determine whether they were commensurate for your comparison (hit ctrl+Enter after executing to view the log).
Logger.log(date_end);
Logger.log(todaysDate.setHours(0,0,0,0));
They weren't comparable at all. Here are the lines I changed to make this work:
var todaysDate = Utilities.formatDate(new Date(), "GMT+1", "MM/dd/yyyy");
var date_end = Utilities.formatDate(date_end_values[i][0], "GMT+1", "MM/dd/yyyy");
if(date_end == todaysDate) {
HTH