Over write data in a column - javascript

With the code that I have below I am trying to copy data over to a new sheet but I want it to always start with A2.
I don't want the data to constantly go to the end, I want it to always start in A2. Further more, where the issue comes in is I have formulas in B2:N200 so the data constantly tries to copy to the end.
Originally the code looked like this:
if(data[n][0]){
var dest = ss.getSheetByName(data[n][0].toString().replace(/ /g,''));//find the destination sheet
Logger.log(data[n][0].toString().replace(/ /g,''))
var destRange = dest.getRange(dest.getLastRow()+1,1);// define range
master.getRange(selectedfirstRow+n,2,1,1).copyTo(destRange);// and make copy below last row
}
}
And I realized that the Var destRange was defining where to start inputting the data.
if(data[n][0]){
var dest = ss.getSheetByName('Sunday'.replace(/ /g,''));//find the destination sheet
Logger.log(data[n][0].toString().replace(/ /g,''))
var destRange = dest.getRange(2+1,1);// define range
master.getRange(selectedfirstRow+n,2,1,1).copyTo(destRange);// and make copy below last row
}
}
As you can see I changed the getRange to (2+1,1); It does go to the next row each time I run the function but it only inputs one piece of data rather than consistenly going to the next.
EDIT
And I guess I should ask instead, how do I get the last empty cell in the first column only rather than the entire sheet. I know that the code currently is looking at the last row for the whole sheet, how do I get it to just find the first column?

Get only the first column of data, and then find the first empty element in the array.
Get a 2D array (Arrays inside of one outer array):
//Get the data from the first column only
columnOneData = dest.getRange(1,1,dest.getLastRow()).getValues();
That 2D array needs to be collapsed into an 1D array:
columnOneData = columnOneData.toString();//Convert the 2D array to a comma seperated string
columnOneData = columnOneData.split(",");//Convert the string to a 1D array
Find the first empty element in the new array:
firstRowWithEmptyCell = columnOneData.indexOf("") + 1;//Find the first empty element
Put together:
function test() {
var columnOneData,data,dest,destRange,firstRowWithEmptyCell,n,selectedfirstRow,ss;
ss = SpreadsheetApp.getActive();
if(data[n][0]){
dest = ss.getSheetByName('Sunday'.replace(/ /g,''));//find the destination sheet
//Logger.log(data[n][0].toString().replace(/ /g,''))
columnOneData = dest.getRange(1,1,dest.getLastRow()).getValues();//Get the data from the first column only
columnOneData = columnOneData.toString();//Convert the 2D array to a comma seperated string
columnOneData = columnOneData.split(",");//Convert the string to a 1D array
Logger.log('columnOneData: ' + columnOneData)
firstRowWithEmptyCell = columnOneData.indexOf("") + 1;//Find the first empty element
Logger.log('firstRowWithEmptyCell: ' + firstRowWithEmptyCell)
destRange = dest.getRange(2+1,1);// define range
master.getRange(selectedfirstRow+n,2,firstRowWithEmptyCell,1).copyTo(destRange);// and make copy below last row
}
}

Related

Copy filtered range from one spreadsheet to another - Google app script

I have a large google sheet with 30275 rows and 133 columns in a google sheet. I want to filter the data and copy column AZ to another spreadsheet.
Link to spreadsheet: https://docs.google.com/spreadsheets/d/1aiuHIYzlCM7zO_5oZ0aOCKDwPo06syXhWvhQMKgJE2I/edit?usp=sharing
I have been trying to follow this link
I am not that familiar with javascript and the code is designed to exclude items from filter rather than including items on filter. I have 500+ items to exclude so need to work out something that will be efficient in filtering large dataset in short time before execution limit is reached.
Here is my code so far. Any help to get this working would be appreciated.
NOTE: Filter/ Query with importrange formulas dont work due to the large volume of data. So I need an efficient script to filter large dataset and move them to another sheet before execution time limit.
function filtered() {
var ss = SpreadsheetApp.openById('1u9z_8J-tvTZaW4adO6kCk7bkWeB0pwPcZQdjBazpExI');
var sheet = ss.getSheetByName('Sheet1');
var destsheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('JockeyList');
var demosheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Betting data - Demo');
var jockey = demosheet.getRange('L14').getValues();
// Get full (non-filtered) data
var values = sheet.getRange('A:EC').getValues();
// Apply filter criteria here
//Logger.log(jockey);
var hiddenValues = jockey;
values = values.filter(function(v) {
return hiddenValues.indexOf(v[51]) == 1;
});
Logger.log(values.length);
// Set filtered data on the target sheet
destsheet.getRange(10, 5, values.length, 2).setValues(values);
}
Ok so it seems like you want to copy only the values from AZ in 'Sheet1' that are equal to whatever string value is contained in cell L14 of sheet 'Betting data - Demo.' If that is the case, then here is a change to your original code that will accomplish that:
function filtered() {
var ss = SpreadsheetApp.openById('1u9z_8J-tvTZaW4adO6kCk7bkWeB0pwPcZQdjBazpExI');
var sheet = ss.getSheetByName('Sheet1');
// this assumes that your destsheet and demosheet are in the same spreadsheet. Keep in mind that opening spreadsheets with SpreadsheetApp is costly so you want to minimize your calls to new sheets.
var destsheet = ss.getSheetByName('JockeyList');
var demosheet = ss.getSheetByName('Betting data - Demo');
var jockey = demosheet.getRange('L14').getValue();
var searchTerm = new RegExp(jockey);
// Get full (non-filtered) data
var values = sheet.getRange('A:EC').getValues();
// Apply filter criteria here and return ONLY THE VALUE IN COLUMN AZ
var filteredValues = values.reduce(function(resultArray, row) {
if (searchTerm.test(row[51])) resultArray.push([row[51]]);
return resultArray;
}, [])
// Set filtered data on the target sheet
// Note* not clear why you are starting at row 10, but as is this will overwrite all of the data in column 5 of destsheet starting from row 10 every time this function runs
destsheet.getRange(10, 5, filteredValues.length, 1).setValues(filteredValues);
}
As it says in the code sample, this will only copy and paste the value in column AZ of 'sheet1'. It does not alter 'sheet1' in any way. If that is really all you want to do, then this function works, but it's overkill. Since you are just filtering values in AZ against a single string value, it would be more efficient to simply count the number of times that string occurs in column AZ and then add the string that number of times to your destination sheet.
Also note that your original function is pasting values into destsheet into a constant row (row 10). That means that every time your function runs, the data from row 10 on will be overwritten by whatever data you are copying from 'sheet1'

Using If function for multiple cells

Hi I have a working program to pull data from one sheet to another sheet and place in the relevant cells, however with one column I want to change the results which reads a "K" from the source sheet and write an "A" to the target sheet using a if function but I can only seem to do one cell and not the full column. How can I do this for multiple cells? If I try.getRange("F18:41") it doesn't seem to work.
Please see the code below:
var sss = SpreadsheetApp.openById('....'); // sss = source spreadsheet
var ss = sss.getSheetByName('.....); // ss = source sheet
//Get full range of data sheet 1
var TypeWire = ss.getRange("F18");
//get A1 notation identifying the range
var A16Range = TypeWire.getA1Notation();
//get the data values in range
var SDataSixteen = TypeWire.getValues();
var tss = SpreadsheetApp.openById('.....'); // tss = target spreadsheet
var ts = tss.getSheetByName('....'); // ts = target sheet
//set the target range to the values of the source data
ts.getRange("C40:C61").setValues(SDataSeven);
if (SDataSixteen == "K")
{
ts.getRange("L16").setValue("A");
}
}
The getValues() method of Class Range returns a multidimentional (2D) array. The elements of the "outer" array are arrays that represent rows. The elements of the inner arrays are objects that represent the cell values for the corresponding row.
There are several ways to do what you are looking for. Perhaps the easier to understand is the technique shown in the Cooper's answer: Use nested for statements.
Use one for statement to iterate over the rows, then another for loop to iterate over the row cells.
IMPORTANT NOTE:
Using loops to write single cells values is very slow. For recommendations please read https://developers.google.com/apps-script/guides/support/best-practices
Related
Hide Row in Google Sheets if Cell Contains "no" - Multiple Sheets
How to compare values of cells in if condition?

Write single value on multiple rows in Google Apps Script

I'm new to Google Apps Script and I'm trying to make a script where I'll take a single string value and copy to multiple rows in a google sheet. I've taken an array to save the single value multiple times. But still I can't get it done. Every time I run the script, I get this error,
Cannot convert Array to Object[][]
Here are my codes,
function myFun() {
var ss = SpreadsheetApp.openById(SHEET_ID);
var sheet = ss.getSheetByName("Form Responses");
var new_vals = sheet.getRange(2, 1, sheet.getLastRow(), sheet.getLastColumn()).getValues();
var master_ss = SpreadsheetApp.getActiveSpreadsheet();
var master_sheet = master_ss.getSheetByName("Sheet1");
var lr = master_sheet.getLastRow()+1;
var ss_real_name = "District";
var ss_real_names = [];
for (var i=0; i<new_vals.length; i++)
{
ss_real_names.push(ss_real_name);
}
master_sheet.getRange(lr, 1, new_vals.length).setValues(ss_real_names);
}
Is there something wrong in my code? How can I save the single string value in multiple rows?
Google Apps script writes values as arrays of arrays with every array inside of the outer array being a row and the elements in the inner arrays going into the columns.
If you want to write the data as rows you need to create an array filled with one element arrays. Try ss_real_names.push([ss_real_name]);.
If you wanted to write them as a column vector you could just say setValues([ss_real_names]) instead.

using google's data.join to interatively add data to a graph

I'm trying to build a set of data for a Google scatter graph using data.join as follows:
var tempData = newData();
var tempData2 = totalData;
dataArray[dataCount] = tempData;
var joinMark = countArray(dataCount);
totalData = google.visualization.data.join(tempData2,tempData,'full',[[0,0]],[joinMark],[1]);
dataCount = dataCount+1;
Where newData() generates a dataTable from a database, column 0 is always a date and column 1 is always a number. I have been able to get this to work once, to display 2 variables on the graph, but trying to add any more causes my code to fail.
BTW totalData is the variable passed to chart.draw()
The countArray function returns 1 if both arrays have 2 columns (works fine), but for further additions I am returning a comma separated string 1,2... 1,2,3.. etc. This is based on my assumption that that last two variables in data.join are the column numbers from dataTable 1 and 2 respectively to be combined. Am I right in this assumption, or do I need a different variable in that location?
Thanks
Tom
You are correct about the function of the last two parameters in the join call, but you do not want to pass a comma-separated string where joinMark is: that should be an array of column indices, not an array containing a string. You cannot add a comma-separated string to an array to get an array on integers:
var joinMark = '1,2,3';
[joinMark] == [1,2,3]; // false
Change your countArray function to return an array of integers instead, and then pass that array directly to the join function (that is, you shouldn't wrap it in brackets to create an array of arrays):
var joinMark = countArray(dataCount);
totalData = google.visualization.data.join(tempData2,tempData,'full',[[0,0]],joinMark,[1]);

indexOf returning -1 despite object being in the array - Javascript in Google Spreadsheet Scripts

I am writing a script for a Google Docs Spreadsheet to read a list of directors and add them to an array if they do not already appear within it.
However, I cannot seem to get indexOf to return anything other than -1 for elements that are contained within the array.
Can anyone tell me what I am doing wrong? Or point me to an easier way of doing this?
This is my script:
function readRows() {
var column = SpreadsheetApp.getActiveSpreadsheet().getRangeByName("Director");
var values = column.getValues();
var numRows = column.getNumRows();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var directors = new Array();
for (var i = 0; i <= numRows - 1; i++) {
var row = values[i];
if (directors.indexOf(row) == -1) {
directors.push(row);
} else {
directors.splice(directors.indexOf(row), 1, row);
}
}
for (var i = 2; i < directors.length; i++) {
var cell = sheet.getRange("F" + [i]);
cell.setValue(directors[i]);
}
};
When you retrieve values in Google Apps Script with getValues(), you will always be dealing with a 2D Javascript array (indexed by row then column), even if the range in question is one column wide. So in your particular case, and extending +RobG's example, your values array will actually look something like this:
[['fred'], ['sam'], ['sam'], ['fred']]
So you would need to change
var row = values[i];
to
var row = values[i][0];
As an aside, it might be worth noting that you can use a spreadsheet function native to Sheets to achieve this (typed directly into a spreadsheet cell):
=UNIQUE(Director)
This will update dynamically as the contents of the range named Director changes. That being said, there may well be a good reason that you wanted to use Google Apps Script for this.
It sounds like an issue with GAS and not the JS. I have always had trouble with getValues(). Even though the documentation says that it is a two dimensional array, you can't compare with it like you would expect to. Although if you use an indexing statement like values[0][1] you will get a basic data type. The solution (I hope there is a better way) is to force that object into a String() and then split() it back into an array that you can use.
Here is the code that I would use:
var column = SpreadsheetApp.getActiveSpreadsheet().getRangeByName("Director");
var values = column.getValues();
values = String(values).split(",");
var myIndex = values.indexOf(myDirector);
If myDirector is in values you will get a number != -1. However, commas in your data will cause problems. And this will only work with 1D arrays.
In your case: var row = values[i]; row is an object and not the string that you want to compare. Convert all of your values to an array like I have above and your comparison operators should work. (try printing row to the console to see what it says: Logger.log(row))
I ran into a similar problem with a spreadsheet function that took a range as an object. In my case, I was wanting to do a simple search for a fixed set of values (in another array).
The problem is, your "column" variable doesn't contain a column -- it contains a 2D array. Therefore, each value is it's own row (itself an array).
I know I could accomplish the following example using the existing function in the spreadsheet, but this is a decent demo of dealing with the 2D array to search for a value:
function flatten(range) {
var results = [];
var row, column;
for(row = 0; row < range.length; row++) {
for(column = 0; column < range[row].length; column++) {
results.push(range[row][column]);
}
}
return results;
}
function getIndex(range, value) {
return flatten(range).indexOf(value);
}
So, since I wanted to simply search the entire range for the existance of a value, I just flattened it into a single array. If you really are dealing with 2D ranges, then this type of flattening and grabbing the index may not be very useful. In my case, I was looking through a column to find the intersection of two sets.
Because we are working with a 2D array, 2dArray.indexOf("Search Term") must have a whole 1D array as the search term. If we want to search for a single cell value within that array, we must specify which row we want to look in.
This means we use 2dArray[0].indexOf("Search Term") if our search term is not an array. Doing this specifies that we want to look in the first "row" in the array.
If we were looking at a 3x3 cell range and we wanted to search the third row we would use 2dArray[2].indexOf("Search Term")
The script below gets the current row in the spreadsheet and turns it into an array. It then uses the indexOf() method to search that row for "Search Term"
//This function puts the specified row into an array.
//var getRowAsArray = function(theRow)
function getRowAsArray()
{
var ss = SpreadsheetApp.getActiveSpreadsheet(); // Get the current spreadsheet
var theSheet = ss.getActiveSheet(); // Get the current working sheet
var theRow = getCurrentRow(); // Get the row to be exported
var theLastColumn = theSheet.getLastColumn(); //Find the last column in the sheet.
var dataRange = theSheet.getRange(theRow, 1, 1, theLastColumn); //Select the range
var data = dataRange.getValues(); //Put the whole range into an array
Logger.log(data); //Put the data into the log for checking
Logger.log(data[0].indexOf("Search Term")); //2D array so it's necessary to specify which 1D array you want to search in.
//We are only working with one row so we specify the first array value,
//which contains all the data from our row
}
If someone comes across this post you may want to consider using the library below. It looks like it will work for me. I was getting '-1' return even when trying the examples provide (thanks for the suggestions!).
After adding the Array Lib (version 13), and using the find() function, I got the correct row!
This is the project key I used: MOHgh9lncF2UxY-NXF58v3eVJ5jnXUK_T
And the references:
https://sites.google.com/site/scriptsexamples/custom-methods/2d-arrays-library#TOC-Using
https://script.google.com/macros/library/d/MOHgh9lncF2UxY-NXF58v3eVJ5jnXUK_T/13
Hopefully this will help someone else also.
I had a similar issue. getValues() seems to be the issue. All other methods were giving me an indexOf = -1
I used the split method, and performed the indexOf on the new array created. It works!
var col_index = 1;
var indents_column = main_db.getRange(1,col_index,main_db.getLastRow(),1).getValues();
var values = String(indents_column).split(","); // flattening the getValues() result
var indent_row_in_main_db = values.indexOf(indent_to_edit) + 1; // this worked
I ran into the same thing when I was using
let foo = Sheet.getRange(firstRow, dataCol, maxRow).getValues();
as I was expecting foo to be a one dimensional array. On research for the cause of the apparently weird behavior of GAS I found this question and the explanation for the always two dimensional result. But I came up with a more simple solution to that, which works fine for me:
let foo = Sheet.getRange(firstRow, dataCol, maxRow).getValues().flat();

Categories

Resources