Google apps script select specific columns to upload into target sheet - google-apps-script

Total beginner here. I am trying to select columns A,B,C from spreadsheet B which has around 40K rows and 25 columns, to spreadsheet A which is a blank document. So, I have two spreadsheets.
This code works fine but I want to select only the columns I need (columns including all the data, not just the headers).
function importdata() {  
let ss = SpreadsheetApp.openById("ID"); //SPREADSHEET TO COPY FROM  
let sheet = ss.getSheetByName("name"); //SHEET (TAB) TO COPY FROM  
sheet.getRange(1,1,sheet.getLastRow(),sheet.getLastColumn()).getValues();
let ssThis = SpreadsheetApp.getActiveSpreadsheet();
let sheetRawData = ssThis.getSheetByName("name"); //SHEET IN THE TARGET SPREADSHEET TO COPY TO
sheetRawData.getRange(1,1,sheetRawData.getLastRow());
}
Any idea as to how I can add this into the code above?
Many thanks!

You can create an array of selected columns and get / set the values for the ranges corresponding to those columns:
function importSelectedColumns() {
let selectedColumns = [1, 3, 5];
let ss = SpreadsheetApp.openById("ID"); //SPREADSHEET TO COPY FROM
let sheet = ss.getSheetByName("name"); //SHEET (TAB) TO COPY FROM
let ssThis = SpreadsheetApp.getActiveSpreadsheet();
let sheetRawData = ssThis.getSheetByName("name"); //SHEET IN THE TARGET SPREADSHEET TO COPY TO
selectedColumns.forEach(function(column){
let data = sheet.getRange(1,column, sheet.getLastRow(),1).getValues();
sheetRawData.getRange(1,column, sheet.getLastRow(), 1).setValues(data);
})
}
Explanation:
forEach() is one of several possibilities to loop through several columns subsequently.
getRange(row, column, numRows, numColumns) lets you specify the number and amount of columns to retrieve.
setValues(values) allows you to import the data from one range into another one.
Note: The range dimensions of the origin and destination ranges need to match.
Additional information:
If you would like to paste your data into an adjacent range starting with column 1, one possible way based on the sample above would be to redefine the loop as following:
selectedColumns.forEach(function(column,i ){
let data = sheet.getRange(1,column, sheet.getLastRow(),1).getValues();
sheetRawData.getRange(1,1+i, sheet.getLastRow(), 1).setValues(data);
})
Thereby the counter variable i is introduced and the notation of the destination column is modified from column to 1+i, meaning that the columns will be set starting with column 1 and increasing by 1 for each loop iteration.

Related

Google Sheets, fill data from form sheet into specific cells on other sheets

I'm new to coding in general (other than experience with MATLAB which I don't think counts) but I'm starting with trying to code in the Google Sheets API for some advanced functionality.
The code I'm trying to write is for a spreadsheet that I track all my car expenses on. I have it doing a bunch of number crunching for MPG currently, but don't want to have to find the row and column each time to enter the date. Instead I'd like one sheet that is clean and simple that I enter the variables on (Miles driven, gallons pumped, price per gallon, estimated MPG from the car computer) and it fills the other sheets in the document with that information automatically when I hit save, then clears the form so I can do it again next time.
Here is what I have so far.
function submitData() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var formSS = ss.getSheetByName('Fill-Up'); //Form Sheet
var datasheet1 = ss.getSheetByName('Mileage Stats'); //Data Sheet 1
var datasheet2 = ss.getSheetByName('Costs and Savings'); //Data Sheet 2
//Input Values 1
var values1 = [[formSS.getRange('B3').getValue(),
formSS.getRange('B6').getValue()]];
datasheet1.getRange(datasheet1.getLastRow()+1, 2, 1, 2).setValues(values1);
//Input Values 2
var values2 = [[formSS.getRange('B4').getValue(),
formSS.getRange('B5').getValue()]];
datasheet2.getRange(datasheet2.getLastRow()+1, 2, 1, 2).setValues(values2);
}
It works with the exception of two issues that I haven't been able to solve yet.
1) It writes the information to a new row at the bottom of the page, not the next empty row.
2) It isn't writing the information in B6 to the correct cell. I want B3 written to column B in "Mileage Stats" sheet, and it is, B4 is written to column B in "Costs and Savings" as I want, and B5 is written to column C in "Costs and Savings" as I want, but B6 is written to column C in "Mileage Stats" but I want it in column G, and can't figure out how to change that with my current code, or any other code I can find.
Any help anyone can give would be awesome!
Are you using any ArrayFormulas on the sheets that you are trying to use getLastRow()? If so, ArrayFormula will add data into the cells for the whole range.
You may want to look at using the Sheet.appendRow() method like below and remove all the empty rows on your data sheets. appendRow() will add a new row at the bottom of the sheet with that data passed to the method.
datasheet1.appendRow(values1);
datasheet2.appendRow(values2);
Cells with functions are counted as data cells, that's why you're inserting the rows at the bottom of the sheet. To solve this, you can use getNextDataCell() method to a column range without functions (e.g. a cell in column B), which returns the last cell with data for a given direction. I tested the below code and worked for inserting the data in the last row with data in column B:
function submitData() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var formSS = ss.getSheetByName('Fill-Up'); //Form Sheet
var datasheet1 = ss.getSheetByName('Mileage Stats'); //Data Sheet 1
var datasheet2 = ss.getSheetByName('Costs and Savings'); //Data Sheet 2
//Input Values 1
var values1 = [[formSS.getRange('B3').getValue(),
formSS.getRange('B6').getValue()]];
var lastRowInB = datasheet1.getRange("B6").getNextDataCell(SpreadsheetApp.Direction.DOWN).getLastRow();
datasheet1.getRange(lastRowInB+1, 2, 1, 2).setValues(values1);
//Input Values 2
var values2 = [[formSS.getRange('B4').getValue(),
formSS.getRange('B5').getValue()]];
lastRowInB = datasheet1.getRange("B7").getNextDataCell(SpreadsheetApp.Direction.DOWN).getLastRow();
datasheet2.getRange(lastRowInB+1, 2, 1, 2).setValues(values2);
}

How to display the values in columns in Google app script

I got the output as below (row wise):
one
two
three
But I would like to display the value as below (column wise, single value in each cell):
one two three
Can any one please tell me how can I achieve this using getRange function in Google app script ?
Thanks.
Unless you are setting only 1 value, I recommend using getRange(startRow, startCol, numRows, numCols) together with Range class methods getValues() and setValues().
getValues() produces a 2d array which you can access with indexes (let's use integer variables row and col in our example) data[row][col]
So let's say you wish to set one, two, three to column A, B and C in row 1, then you simply have to do
var targetRange = SpreadsheetApp.getActiveSheet().getRange(1, 1, 1, 3)
var data = [['One', 'Two', 'Three']]
targetRamge.setValues(data)
Now let's say I want to write One, Two and Three into Column A over rows 1 2 and 3 then it is only slightly different:
var targetRange = SpreadsheetApp.getActiveSheet().getRange(1, 1, 3, 1) //we now get 1 column, but 3 rows
var data = [['One'], ['Two'], ['Three']] //Each array inside of the main array is a new row
targetRamge.setValues(data)
And there you have it. Simply manipulate the data as a 2D array all the time and use .getValues() and .setValues() with a range that uses multiple rows and/or columns.
Not sure if this is helpful. Have you heard about appendRow()? This will add your array to the last row of the sheet.
function append() {
var arr = ["a","b","c"]
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Entities')
sheet.appendRow(arr)
}

Google Scripts copyto issue

I am trying to get a row with a certain range to copy into the row after text ends. I had it working a few days ago, but cannot figure out where I am going wrong right now.
So far I have:
function getNextRow();
return SpreadsheetApp.getActiveSpreadsheet().getLastRow()+1;
}
function test() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var range = ss.getRange('a4:e4')
var data = range.getValues();
var nextrow = getNextRow();
ss.getRange(nextrow).setValues(data);
}
I have attempted the copyto, but cannot seem to figure it out again from the google developer's page. Any help is appreciated, thank you!
For one thing, you never specify the sheet you are working with. Which sheet of the spreadsheet should this script act on? Use getActiveSheet to pick the active one, or getSheetByName to pick a particular sheet.
Also, your function getNextRow returns an integer, which is the number of the first row that's below all the data. So far so good. But then you call ss.getRange(nextrow) where nextrow is that integer... not good. This isn't one of the acceptable ways of using this method: it needs either A1 notation, or (row, column) pair of integers for a single cell, or (row, column, number of rows, number of columns) quadruple for a range of more than one cell. Which is what you have, so use
ss.getRange(nextrow, 1, data.length, data[0].length).setValues(data);
This says: starting in the row nextrow, column 1 (meaning A), select the range of same size as data. The pair data.length, data[0].length is how one gets the height and width of data array.
That said, there is an easier way to achieve what you want, using appendRow method. Here's a function that would replace all of your code:
function test() {
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getRange('a4:e4')
var data = range.getValues();
sheet.appendRow(data[0]);
}
This appends the content of A4:E4 in the active sheet to the bottom of the same sheet. The method appendRow takes a one-dimensional array, hence data[0] and not just data (which is two-dimensional).

Google Script to copy specific columns from one sheet to another sheets last row onEdit

I am looking for some help on google app scripting. Currently I have a spreadsheet that has 3 sheets. First sheet is data that comes from a google form. Second sheet is an "open" tab and third is a "closed" tab.
When data comes into the spreadsheet from the form it has only the columns that the form has. The "open" sheet has a combination of data from the form (sheet 1) and some additional cells to add more information to by me and not the person submitting the form. Because of this column miss-match I cannot just copy a whole row from sheet 1 to sheet 2. This also needs to be done onEdit trigger. So when an edit trigger fires, I want to store that rows data into memory and then copy column B to the last row of tab 2, column C. Column C > E, column D > B. etc..
How would I store the whole row into memory (an array I presume), and then copy only specific cells, in a specific order into the last row of a different sheet?
Hope that makes sense :-/
As you said, you'll have to use arrays to get data and write it back to another sheet in your selected order.
This is pretty basic manipulation and there are many ways to achieve it.
One way that is very easy to understand is as follow :
get row data in an array
pick up each value one by one and store in another array
write back to the last row +1 on another sheet.
Note that arrays are indexed starting from 0 , rows and columns start from 1 and A so you'll have to do some math !
function copyRow(){
var ss = SpreadsheetApp.getActive();
var sheet = ss.getActiveSheet();
var rowIdx = sheet.getActiveRange().getRowIndex();
var rowValues = sheet.getRange(rowIdx,1,1,sheet.getLastRow()).getValues();
Logger.log(rowValues);
var destValues = [];
destValues.push(rowValues[0][0]);// copy data from col A to col A
destValues.push(rowValues[0][2]);// copy data from col C to col B
destValues.push(rowValues[0][1]);// copy data from col B to col C
destValues.push(rowValues[0][3]);// copy data from col D to col D
// continue as you want
var dest = ss.getSheets()[1];//go on chosen sheet (here is the 2cond one)
dest.getRange(dest.getLastRow()+1,1,1,destValues.length).setValues([destValues]);//update destination sheet with selected values in the right order, the brackets are there to build the 2D array needed to write to a range
}
If you want that function to run on edit then just call it onEdit() and you're done !
Source: https://stackoverflow.com/a/64297866/14427194
function onEdit(e) {
//e.source.toast("Entry");
//console.log(JSON.stringify(e));
const sh=e.range.getSheet();
if(sh.getName()=="Sheet1" && e.range.columnStart==20 && e.value=="TRUE") {
const tsh=e.source.getSheetByName('Sheet2');
const nr=tsh.getLastRow()+1;
sh.getRange(e.range.rowStart,1,1,12).moveTo(tsh.getRange(nr,1,1,12));
sh.getRange(e.range.rowStart,16,1,4).moveTo(tsh.getRange(nr,16,1,4));
sh.deleteRow(e.range.rowStart);
}
}

How to copy row ranges in Google docs?

I have a Spreadsheet, like excel on Google Docs. I am using both Mozilla Firefox and Google Chrome, whichever works. Almost all my columns have dropdown list validation(you know, each cell has a dropdown list to select, I hope I made it clear). I arranged them when I first created the spreadsheet, gave all the columns validation from ranges I created.
My problem is, whenever I add a new row, that row doesn't have any validations, all of them are gone. The old rows still have the validations.
So then, I set the validations every time I add a new row, one by one. This is frustrating. Some people also had the same problem, asked online, but no one answered.
When I copy an empty row with validations and paste it on the new row, it works fine. So, what I am saying is, can you help me write a script for it? Like copying 5 rows when I execute the script?
I am trying to study the scripts but I did nothing nothing so far. I think
var actSc = SpreadsheetApp.getActiveSpreadsheet();
var range = actSc.getRange("A1:B1");
This all I got from the examples I saw. I mean it. I got nothing.
If this copies the ranges of one cell, then I guess I should do it for all my columns.
But how do I put them in the new row? Is there something like setRange?
I could really use some help. This is driving me crazy and I really don't get this script thing.
What I mean by range is that I have ranges like "STATES" and it includes "NY,LA,CA" etc. This NY,LA,CA fills the dropdown list in the cells of that STATES column. I hope this getRange means this range.
Sorry about my English.
If I understand correctly, you want to script a function that will add new rows to a sheet and maintain the existing validations for your columns. This is certainly possible and not too difficult. One approach could be a "refresh validations" function that updates your entire sheet all at once, in the event that you want to reuse it in other sheets. First, though, it sounds like you could use a brief overview of the object classes you need to know about to do basic Google Apps Scripts:
SpreadsheetApp - Think of this class as the foundation of the Spreadsheet Service. It provides file I/O and functionality that is not tied to specific spreadsheets, per se, such as UI and the creation of Data Validation sets. It's the interface to all of your individual spreadsheet documents.
Spreadsheet - A spreadsheet document file, which can contain multiple Sheets. This is what gets created when you create a new Google Sheets document in Drive. Provides document-level functions, such as the ability to manage ownership, set permissions, access metadata, etc. There's some overlap with the Sheet class, so this one can seem like a bit of a mishmash.
Sheet - An individual sheet is what you normally think of as a spreadsheet: a set of rows and columns. Each Spreadsheet document can contain many, distinct Sheets. The Sheet class lets you modify the overall appearance of the sheet. You can freeze or hide rows, protect ranges of cells from being edited, add/delete rows and columns, etc. You can also get data about the sheet, such as the last row that has content or the maximum range of the whole sheet.
Range - Dropping down another level, we reach the Range object, which represents a certain rectangular area of cells. This can be as small as a single cell or as large as the whole sheet. It does not seem possible, however, for Ranges to represent discontiguous cells. This is where you had some trouble, because you treated the Range object as content that you could copy and paste in your sheet, which is understandable. But a Range isn't the data in the cells it represents. It's just an interface to those cells. If you want to access the data itself, you have to drop down to the bottom level of the hierarchy:
Value - The actual contents of your sheets are normal JavaScript values: strings, integers, Booleans, etc. that you can manipulate with the subset of JavaScript that Google Apps Script supports.
In order to do something with the values in your sheet, you first get the Range object from the Sheet (which you get from the SpreadsheetApp) and then get the values from the Range:
var values = SpreadsheetApp.getActiveSheet().getRange("A1:B1").getValues(); // returns [[]]
Note that getValues() returns a multi-dimensional array. As a representation of the values in your sheet, it looks like this:
// row 1 [[column A, column B, column C, column D, ...],
// row 2 [column A, column B, column C, column D, ...],
// row 3 [column A, column B, column C, column D, ...],
// row 4 [column A, column B, column C, column D, ...],
// row 5 [column A, column B, column C, column D, ...], ...]
So if the range A1:B1 is a range of one row and two columns, you can retrieve the values with A1 notation or by specifying the upper left row and column of the range, and the number of rows and number of columns you want to retrieve:
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getRange("A1:B1");
var range = sheet.getRange(1, 1, 1, 2); // row 1, column 1, 1 row, 2 columns
var values = range.getValues(); // returns [[50, 100]]
If the value in A1 is 50, and the value in B1 is 100, the last function above will return [[50, 100]]. You can access individual cell values directly, too:
var range = sheet.getRange("A1");
var value = range.getValue(); // returns 50
var cell = range.getCell().getValues(); // returns [[50]]
Obviously, you can set the values of ranges, too:
var range = sheet.getRange("A1:B2");
range.setValues([[50, 100]]);
range = sheet.getRange(1, 1); // same as sheet.getCell(1, 1)
range.setValue(50); // the value of A1, or row 1 column 1, is now 50
The next step is to figure out how the Data Validation class works. You create a Data Validation object using the Data Validation Builder, which lets you chain together a series of rules to apply to a range. You then set the range to that Data Validation rule set:
var stateList = ["AK", "AL", "AR", ...];
var rules = SpreadsheetApp.newDataValidation() // create a new Data Validation Builder object and use method chaining to add rules to it
.requireValueInList(stateList, true) // first param is the list of values to require, second is true if you want to display a drop down menu, false otherwise
.setAllowInvalid(false) // true if other values are allowed, false otherwise
.setHelpText("Enter a state") // help text when user hovers over the cell
.build();
range.setDataValidation(rules); // apply the rules to a range
Now you can insert rows and the rules should copy over into them automatically:
var lastRow = sheet.getLastRow(); // get the last row that contains any content
sheet.insertRowAfter(lastRow);
Or copy the rules and use them elsewhere:
var cell = sheet.getRange(1, 1, 1, 1);
var rule = sheet.getDataValidation(); // returns rule
var range = sheet.getRange("A1:B1");
var rules = range.getDataValidations(); // returns [[rules, rules]]
var lastRow = sheet.getLastRow(); // or sheet.getMaxRows()
range.setDataValidations(rules);
So you can very easily put these concepts together to write whatever sort of function you need to add rows, build validation rule sets, and add validations to new ranges of cells. You can do most of these things more concisely than I have here, but it sounds like you're looking for a more in-depth explanation. I hope it helps.
var sheetToUpdate = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
sheetToUpdate.insertRowAfter(sheetToUpdate.getLastRow());
var rangeToUpdate = sheetToUpdate.getRange(sheetToUpdate.getLastRow()+1,1,1,sheetToUpdate.getMaxColumns());
sheetToUpdate.getRange(sheetToUpdate.getLastRow(),1,1,sheetToUpdate.getMaxColumns()).copyTo(rangeToUpdate, {formatOnly:true});