Copy filter data from one spreadsheet file to another - Google Apps Script - google-apps-script

I'm currently working on a project where I need to copy data to another google sheet.
let me explain:
I'd created a function where I applied filter by text and it works. But the issue is that I can't copy only the filtered data to another sheet. I'd seen many stack conversations but nothing fit.
here is the code
function copyWithValues() {
const spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
const sourceSheet = spreadSheet.getSheetByName('testo');
const sourceRange = sourceSheet.getDataRange();
const sourceValues = sourceRange.getValues();
const targetSpreadsheet = titleAsDate();
let rowCount = sourceValues.length;
let columnCount = sourceValues[0].length;
let targetSheet = targetSpreadsheet.getSheetByName('Sheet1').setName("Report");
let targetRange = targetSheet.getRange(1, 1, rowCount, columnCount);
targetRange.setValues(sourceValues);
}

Explanation:
The following solution is inspired by this answer.
The latter has one limitation though, it only works for transferring the filter data between sheets of the same spreadsheet.
We are going to use the exact same answer to copy the filter values from the source sheet and paste them to a temporary sheet temp_sheet of the source spreadsheet file.
Then we simply get the values of that temporary file and paste them to another spreadsheet file with the regular method of getting and setting the values as you have already implemented in your code.
Solution:
function copyWithValues() {
const spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
const sourceSheet = spreadSheet.getSheetByName('testo');
const temp_sheet = spreadSheet.insertSheet('temp_sheet');
const sourceRange = sourceSheet.getFilter().getRange();
sourceRange.copyTo(
temp_sheet.getRange('A1'),
SpreadsheetApp.CopyPasteType.PASTE_NORMAL,
false);
SpreadsheetApp.flush();
const sourceValues = temp_sheet.getDataRange().getValues();
const targetSpreadsheet = titleAsDate();
const rowCount = sourceValues.length;
const columnCount = sourceValues[0].length;
const targetSheet = targetSpreadsheet.getSheetByName('Sheet1').setName("Report");
const targetRange = targetSheet.getRange(1, 1, rowCount, columnCount);
targetRange.setValues(sourceValues);
spreadSheet.deleteSheet(temp_sheet);
}
where the helper function titleAsDate() is defined as:
function titleAsDate() {
const currentDate = Utilities.formatDate(new Date(), "GMT+8", "dd-MM-yyyy HH:mm:ss");
return SpreadsheetApp.create("Report of the " + currentDate);
}
based on your previous question.

Related

How to copy and paste as values Google Apps Script/Sheets from one spreadsheet to another?

So I have a huge spreadsheet with 9k rows and more than 30 columns. I want to copy this spreadsheet to another spreadsheet (Values only).
Previously I was using this code successfully, but due to the increase in data, the script now times out (1800s +). Is there a way to optimize this script or maybe an alternative option altogether?
function temp() {
var sss = SpreadsheetApp.openById('XYZ'); // sss = source spreadsheet
//var ss = sss.getSheets()[4]; // ss = source sheet
var ss = sss.getSheets(); // ss = source sheet
var id=4; //default number
for(var i in ss)
{
var sheet = ss[i];
if(sheet.getName()== "ABC")
{ id=i;
break;
}
}
console.log(id);
ss=sss.getSheets()[id];
//Get full range of data
var SRange = ss.getDataRange();
//get A1 notation identifying the range
var A1Range = SRange.getA1Notation();
//get the data values in range
var SData = SRange.getValues();
SpreadsheetApp.flush();
var tss = SpreadsheetApp.getActiveSpreadsheet(); // tss = target spreadsheet
var ts = tss.getSheetByName('ABC'); // ts = target sheet
//set the target range to the values of the source data
ts.getRange(A1Range).setValues(SData);
}
I believe your goal is as follows.
You want to reduce the process cost of the script.
In this case, I would like to propose to use Sheets API. This has already been mentioned in the Yuri Khristich's comment. Also, when the benchmark is measured between Spreadsheet service (SpreadsheetApp) and Sheets API, when Sheets API is used for reading and writing the values for Spreadsheet, it was confirmed that the process cost could be reduced. Ref
When Sheets API is used for your script, it becomes as follows.
Modified script:
Before you use this script, please enable Sheets API at Advanced Google services. And please set the source Spreadsheet ID and the sheet names.
function temp() {
var sourceSpreadsheetId = "XYZ"; // Please set the source Spreadsheet ID.
var destinationSpreadsheetId = SpreadsheetApp.getActiveSpreadsheet().getId();
var sourceValues = Sheets.Spreadsheets.Values.get(sourceSpreadsheetId, "ABC").values;
Sheets.Spreadsheets.Values.update({values: sourceValues}, destinationSpreadsheetId, "ABC", {valueInputOption: "USER_ENTERED"});
}
References:
Benchmark: Reading and Writing Spreadsheet using Google Apps Script
Method: spreadsheets.values.get
Method: spreadsheets.values.update
Copy from one spreadsheet to another
function copyfromonetoanother() {
const sss = SpreadsheetApp.getActive();
const dss = SpreadsheetApp.openById("dssid");
const ssh = sss.getSheetByName('Sheet1');
const vs = ssh.getDataRange().getValues();
const dsh = dss.getSheetByName('Sheet1');
dsh.getRange(dsh.getLastRow() + 1,1,vs.length,vs[0].length).setValues(vs);
}
If you wish to select the source range:
function copyfromonetoanother() {
const sss = SpreadsheetApp.getActive();
const dss = SpreadsheetApp.openById("dssid");
const ssh = sss.getSheetByName('Sheet1');
const vs = ssh.activeRange().getValues();
const dsh = dss.getSheetByName('Sheet1');
dsh.getRange(dsh.getLastRow() + 1,1,vs.length,vs[0].length).setValues(vs);
}
This function appends to the bottom of the destination sheet
function appenddatatobottomofdestination() {
const sssId = "source spreadsheet id";
const sss = SpreadsheetApp.openById(sssId);
const dss = SpreadsheetApp.getActive();
const dssId = dss.getId();
const ssh = sss.getSheetByName('Sheet1');//Source sheet
const srg = ssh.getRange(1,1,ssh.getLastRow(),ssh.getLastColumn());
const dsh = dss.getSheetByName("Sheet1");//Destination sheet
var vs = Sheets.Spreadsheets.Values.get(sssId, `${ssh.getName()}!${srg.getA1Notation()}`).values;
const drg = dsh.getRange(dsh.getLastRow() + 1, 1, vs.length,vs[0].length);//appends to bottom of spreadsheet
Sheets.Spreadsheets.Values.update({values: vs}, dssId, `${dsh.getName()}!${drg.getA1Notation()}`, {valueInputOption: "USER_ENTERED"});
}

getsheetbyname with variable cell

I have a sheet called Audit with cell B1 corresponding to a specific shopID.
I have built a sheet with each shopID called ShopID+PrevAudit (555PrevAudit)
When they complete the audit they click a button that should copy values and format to the corresponding sheet i've created but I'm getting hung up on calling the correct sheet based on a B1 entry.
This is what I had been using but it was static and i want to make this easier on myself. I'm not sure why this is so difficult for me. Thanks for any help you can provide.
function copyaudit() {
var source = SpreadsheetApp.openById('SheetID');
var sourceSheet = source.getSheetByName('Audit');
var sourceRange = sourceSheet.getDataRange();
var sourceValues = sourceRange.getValues();
var tempSheet = source.getSheetByName('555PrevAudit');
var tempRange = tempSheet.getRange('A1:L51');
var destination = SpreadsheetApp.openById('SheetID');
sourceRange.copyTo(tempRange); // paste all formats?, broken references
tempRange.offset(0, 0, sourceValues.length, sourceValues[0].length)
.setValues(sourceValues); // paste all values (over broken refs)
}
Using a JS template string, you can generate the sheet name:
`${destID}PrevAudit`
To put it in context:
function copyaudit()
{
const range = 'A1:L51';
let spreadSheet = SpreadsheetApp.openById('SheetID');
let sourceSheet = spreadSheet.getSheetByName('Audit');
let sourceRange = sourceSheet.getRange(range);
// Get B1
let destID = sourceRange.getValues()[0][1];
let destSheet = spreadSheet.getSheetByName(`${destID}PrevAudit`);
sourceRange.copyTo(destSheet.getRange(range));
}

Google Sheets: adjusting targetrange and adding conditon to sourcerange

The following script runs once per hour, and works to add new tickets to the "today" tab from the "Injection" tab (which is a importrange from another sheet that changes every 15 minutes). I would like to add 2 additional steps that I have been struggling with
The target range should be the next free row in the target sheet (Column G), currently it is a fixed value that would overwrite existing data. To further complicate things the target sheet is wiped clean every evening at 00:00, meaning the first free row reverts to G7.
The source range should only take values that have the text "New" in Column X, currently it pulls all values indiscriminately
Thanks in advance for any advice or support
function tickets(){
var sourceSheet = "Injection" ;
var sourceRange = "A4:N504" ;
var targetSheet = "Today" ;
var targetRange = "G7:T507" ;
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName(sourceSheet);
var values = sheet.getRange(sourceRange).getValues(); ss.getSheetByName(targetSheet).getRange(targetRange).setValues(values);
}
function tickets(){
const sourceSheet = "Injection" ;
const targetSheet = "Today" ;
const ss = SpreadsheetApp.getActiveSpreadsheet();
const ssh = ss.getSheetByName(sourceSheet);
const tsh = ss.getSheetByName(targetSheet);
const lock = LockService.getDocumentLock()
try{
lock.waitLock(15000);
SpreadsheetApp.flush()
const COL_X_INDEX = 23;
const newValues = ssh.getDataRange().getValues().filter(row=>row[COL_X_INDEX]==='New');
if(newValues.length>0){
const lastRow = tsh.getRange('G:G').getDataRegion().getValues().length()
const targetRange = tsh.getRange(lastRow+1,1,newValues.length, newValues[0].length)
targetRange.setValues(newValues)
}
} finally{
lock.releaseLock()
}
}

copy from spreadsheet to another spreadsheet with dynamic title

I'm currently working on a project where to I need to copy data from one specific sheet in a spreadsheet to another spreadsheet with a dynamic title ( text with date).
moving the data with ID or by name is ok but with a freshly created spreadsheet seems tuff.
all the function will be in the same app script:
creation
copy
function titleAsDate() {
var currentDate = Utilities.formatDate(new Date(), "GMT+8", "dd-MM-yyyy HH:mm:ss")
SpreadsheetApp.create("Report of the " + currentDate)
}
function copyWithValues() {
let spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
let sourceSheet = spreadSheet.getSheetByName('Sources');
let sourceRange = sourceSheet.getDataRange();
let sourceValues = sourceRange.getValues();
let rowCount = sourceValues.length;
let columnCount = sourceValues[0].length;
let targetSheet = spreadSheet.getSheetById('Target');
let targetRange = targetSheet.getRange(1, 1, rowCount, columnCount);
targetRange.setValues(sourceValues);
}
Explanation:
SpreadsheetApp.create(name) returns a spreadsheet object so you can directly use the output of this function directly without the need of extra code.
The newly generated spreadsheet will have one sheet with the name Sheet1 as when you manually create a new spreadsheet file. Therefore, you can use the sheet.setName(name) function to change the name of the sheet to Target. Also this function returns a sheet object (targetSheet) which can then be used to set the values.
Solution:
This is all the code in one function:
function copyWithValues() {
const spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
const sourceSheet = spreadSheet.getSheetByName('Sources');
const sourceRange = sourceSheet.getDataRange();
const sourceValues = sourceRange.getValues();
const currentDate = Utilities.formatDate(new Date(), "GMT+8", "dd-MM-yyyy HH:mm:ss"); // new code
const targetSpreadsheet = SpreadsheetApp.create("Report of the " + currentDate); // new code
let rowCount = sourceValues.length;
let columnCount = sourceValues[0].length;
let targetSheet = targetSpreadsheet.getSheetByName('Sheet1').setName("Target"); // new code
let targetRange = targetSheet.getRange(1, 1, rowCount, columnCount);
targetRange.setValues(sourceValues);
}
If you want to use titleAsDate as a helper function which will be called by copyWithValues, then you can use this code and execute only copyWithValues:
// helper function, used by copyWithValues
function titleAsDate() {
const currentDate = Utilities.formatDate(new Date(), "GMT+8", "dd-MM-yyyy HH:mm:ss");
return SpreadsheetApp.create("Report of the " + currentDate); // new code
}
// main function, you should execute this function
function copyWithValues() {
const spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
const sourceSheet = spreadSheet.getSheetByName('Sources');
const sourceRange = sourceSheet.getDataRange();
const sourceValues = sourceRange.getValues();
const targetSpreadsheet = titleAsDate(); // new code
let rowCount = sourceValues.length;
let columnCount = sourceValues[0].length;
let targetSheet = targetSpreadsheet.getSheetByName('Sheet1').setName("Target"); // new code
let targetRange = targetSheet.getRange(1, 1, rowCount, columnCount);
targetRange.setValues(sourceValues);
}

Google script for google sheets - Range copy paste special 'add'

i'm really newbie at scripting, i used to do my work with microsoft office that have a special paste "add" feature and now for google sheet i can't really find it.
I will have a source range of C2:C102 and destination at same sheet D2:D102 i want the script (that i can run manually weekly) to copy all the range from source and sum it with the already existing data at D2:D102 (only values).
Here is a small example - Before after
I tried to use this code but ofc it just replaces the values.
function copyCells(){
var thisSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var SourceSheet = thisSpreadsheet.getSheetByName("test");
var SourceRange = thisSpreadsheet.getRange("C2:C102");
var destinationSheet = thisSpreadsheet.getSheetByName("test");
var destinationRange = destinationSheet.getRange("D2:D102");
SourceRange.copyTo(destinationRange, {contentsOnly: true});
}
Any help will be really appreciated :)
Haven't tested the code but try this.
grab values with getValues()
sum the values
copy back values with setValues()
function copyCells(){
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
const SourceSheet = spreadsheet.getSheetByName("test");
const SourceRange = spreadsheet.getRange("C2:C102");
const SourceValues = SourceRange.getValues();
const destinationSheet = spreadsheet.getSheetByName("test");
const destinationRange = destinationSheet.getRange("D2:D102");
const destinationValues = destinationRange.getValues();
for (let i = 0; i < SourceValues.length; i++)
destinationValues[i][0] = parseFloat(destinationValues[i][0]) + parseFloat(SourceValues[i][0])
destinationRange.setValues(destinationValues);
}
REFERENCES
range.getValues()
range.setValues()