Is it possible to generate TSV files in bulk each of which grabbing all the data inside correlative columns within one spreadsheet tab? - google-apps-script

Good morning.
I have a Sheet tab called "Tsv Export" containing 16 columns of data.
I'd like to export all these 16 columns each on a separated tsv file.
If possible, each tsv file should be named as the corresponding exported column number (ex 01.tsv, 02.tsv etc)
The 16 tsv files should be saved in the same drive folder where the Sheets document is located.
Note: the script might support more columns, not just 16, and stop the loop at the first empty column.
Thanks so much

I believe your goal as follows.
You want to retrieve the values from the sheet "Tsv Export" and export each column as the TSV file.
You want to give the value of index + 1 as the filename.
You want to export the file to the same folder with the Spreadsheet.
When the column without no values is retrieved at the loop, you want to stop the script.
You want to achieve this using Google Apps Script.
For this, how about this answer? In this answer, I would like to propose the following flow.
Retrieve the folder.
Retrieve values from sheet of "Tsv Export";
Transpose the retrieved values.
Export each column as the TSV file.
Sample script:
function myFunction() {
const sheetName = "Tsv Export";
// 1. Retrieve the folder.
const ss = SpreadsheetApp.getActiveSpreadsheet();
const folder = DriveApp.getFileById(ss.getId()).getParents().next();
// 2. Retrieve values from sheet of "Tsv Export";
const sheet = ss.getSheetByName(sheetName);
const values = sheet.getDataRange().getValues();
// 3. Transpose the retrieved values.
const converted = values[0].map((_, i) => values.map(r => r[i]));
// 4. Export each column as the TSV file.
for (let i = 0; i < converted.length; i++) {
const v = converted[i];
if (v.every(e => !e)) {
break;
} else {
folder.createFile(`${('0' + (i + 1)).slice(-2)}.tsv`, v.join("\n"), "text/tab-separated-values");
}
}
}
Note:
Please confirm the sheet name again.
When you want to export a column to a row as TSV format, please modify as follows.
From
folder.createFile(`${('0' + (i + 1)).slice(-2)}.tsv`, v.join("\n"), "text/tab-separated-values");
To
folder.createFile(`${('0' + (i + 1)).slice(-2)}.tsv`, v.join("\t"), "text/tab-separated-values");
Please use this script with V8.
References:
getValues()
getParents()
createFile(name, content, mimeType)

Related

Create PDF from defined area instead of whole sheet [duplicate]

I use google spreadsheets to create invoices. I want a script through which I can export a selected range (F1:M44) in PDF format with file name Invoice Number(cell B2) + "invoice".
I have tried codes from stack and from youtube. They were all for exporting sheets, not specific ranges.
This answer is very specific to this question. It includes the range "F1:M44" that is asked for in the question for the range needed to export. Also, the name of the PDF file comes from cell in B2.
It is possible to export a range from your Google Sheet without hiding sheet tabs, rows and columns, or creating a temporary new spreadsheet.
function exportRngToPdf(range,shTabName) {
var blob,exportUrl,name,options,pdfFile,response,sheetTabId,ss,ssID,url_base;
range = range ? range : "F1:M44";//Set the default to whatever you want
shTabName = "Sheet1";//Replace the name with the sheet tab name for your situation
ss = SpreadsheetApp.getActiveSpreadsheet();//This assumes that the Apps Script project is bound to a G-Sheet
ssID = ss.getId();
sh = ss.getSheetByName(shTabName);
sheetTabId = sh.getSheetId();
url_base = ss.getUrl().replace(/edit$/,'');
name = sh.getRange("B2").getValue();
name = name + "invoice"
//Logger.log('url_base: ' + url_base)
exportUrl = url_base + 'export?exportFormat=pdf&format=pdf' +
'&gid=' + sheetTabId + '&id=' + ssID +
'&range=' + range +
//'&range=NamedRange +
'&size=A4' + // paper size
'&portrait=true' + // orientation, false for landscape
'&fitw=true' + // fit to width, false for actual size
'&sheetnames=true&printtitle=false&pagenumbers=true' + //hide optional headers and footers
'&gridlines=false' + // hide gridlines
'&fzr=false'; // do not repeat row headers (frozen rows) on each page
//Logger.log('exportUrl: ' + exportUrl)
options = {
headers: {
'Authorization': 'Bearer ' + ScriptApp.getOAuthToken(),
}
}
options.muteHttpExceptions = true;//Make sure this is always set
response = UrlFetchApp.fetch(exportUrl, options);
//Logger.log(response.getResponseCode())
if (response.getResponseCode() !== 200) {
console.log("Error exporting Sheet to PDF! Response Code: " + response.getResponseCode());
return;
}
blob = response.getBlob();
blob.setName(name + '.pdf')
pdfFile = DriveApp.createFile(blob);//Create the PDF file
//Logger.log('pdfFile ID: ' +pdfFile.getId())
}
There are various strategies that have been used to export part of a Google Sheet to a PDF.
Create a new spreadsheet file with just the wanted content
Create a new sheet tab, put the content in the sheet tab and hide any
other sheet tabs, hide unwanted rows and columns
Build a download URL with a range setting
Use range address
Use a named range - &gid=sheetId&range=NamedRange
Export content to a Google Doc and create a PDF from the Google Doc
Merge G-Sheet content with a template file, and create the PDF from
the template file.
Get a range of content from the Sheet, convert it to HTML and use the
HTML to create the PDF file
I would use the method of building a download URL with the range included in the download URL.
NOTE:
Apps Script runs on Google's servers, and has no access to the user's local device. So, Apps Script can't download a PDF file to the user's local device.
You have to add parameter referring to that range. This example will download range b2:e46 :
https://docs.google.com/spreadsheets/d/{spreadsheet_id}/export?exportFormat=pdf&format=pdf&gridlines=false&size=A4&gid={gid_id}&range=b2:e46
Below are dummy ids:
The {spreadsheet_id} is a long string representing the spreadsheet e.g. 3qT8h59XF67dac7dBL694VLSRPTCQ0_isnP--BBBpnrQ
{gid_id} is the id of the sheet e.g. 2563688945
also change the range as needed e.g. B2:E46 or B:E or 2:46
Solution
To be able to export a specfic range to PDF, as there is no specific tool in Apps Script to do this you will need execute workaround.
The following workaround will automatically copy the range we want to export to a new blank spreadsheet to then be able to export only the exact range.
Why do we need a new spreadsheet?
Well for exporting a range and not getting in the way all the blank cells we will need to hide all the non relevant rows and columns. To achieve that, the easiest way is to paste our desired range in the first cell (A1) of our sheet.
Moreover, by default this will export all the sheets of the spreadsheet so we can only have the sheet of this new range arranged in the first cell to avoid other data to get in between. To avoid deleting the original sheet, the best way to achieve this is to create a new spreadsheet and after the process is done delete it.
Here is the script that solves this problem. It is self explained with comments:
function myFunction() {
// Get the range of cells you want to export
var rangeValues = SpreadsheetApp.getActive().getSheetByName('Sheet1').getRange('D10:F13').getValues();
// Get the Drive folder you want to store your PDF to. Otherwise use root folder (if you dont mind about this)
var folder = DriveApp.getFolderById('FOLDERID');
// Create a blank spreadsheet to be able to export just the range
var destSpreadsheet = SpreadsheetApp.create('PDF');
// Check first if the sheet you are going to create exists. Otherwsie create it and copy paste the range
// we want to export as PDF in the first values of the sheet. I.e if our range is 5 rows and 6 columns we want
// it to be copied from A1 to F5 for example. Then we can hide the rest of columns and rows and export
// what we have left
var sheet2 = destSpreadsheet.getSheetByName('sheet2');
if(!sheet2){
destSpreadsheet.insertSheet('sheet2').getRange('A1:C4').setValues(rangeValues);
var sheet2 = destSpreadsheet.getSheetByName('sheet2');
}
// Hide all the rows and columns that do not have content
sheet2.hideRows(sheet2.getLastRow()+1, sheet2.getMaxRows()-sheet2.getLastRow());
sheet2.hideColumns(sheet2.getLastColumn()+1, sheet2.getMaxColumns()-sheet2.getLastColumn());
// Delete the first sheet that is automatically created when you create a new spreadsheet
destSpreadsheet.deleteSheet(destSpreadsheet.getSheetByName('Sheet1'));
// Export our new spreadsheet to PDF
var theBlob = destSpreadsheet.getBlob().getAs('application/pdf').setName('pdf');
var newFile = folder.createFile(theBlob);
//Delete the spreadsheet we created to export this range.
DriveApp.getFileById(destSpreadsheet.getId()).setTrashed(true);
}
I found this solution for Windows very convenient:
How to Print sheet/range using .gs script in Google Sheets?
It does not need to create a new spreadsheet. Rather, you select the cells on the sheet first, then click a "Print" button, and the selected range is passed to the command that creates the PDF.
I will however create a new temporary sheet in the spreadsheet, not a complete new spreadsheet, copy into it the data from various places in the spreadsheet, then print it, then delete it.
I am using the above parameters in combination with JavaScript.
The parameters look like this:
export?format=pdf&size=A4&fzr=true&portrait=true&fitw=true&gridlines=false&printtitle=false&sheetnames=false&pagenum=UNDEFINED&gid=1215564098&ir=false&ic=false&r1=0&c1=6&r2=44&c2=20&attachment=true
Combined with the JavaScript, this is the result. I have created a bookmark and placed the following JavaScript as the URL.
javascript:var winURL = window.location.href;if(winURL.indexOf('/edit#gid=') > 0)%7Bwindow.location.assign(winURL.replace('/edit#gid=', '/export?format=pdf&size=A4&fzr=true&portrait=true&fitw=true&gridlines=false&printtitle=false&sheetnames=false&pagenum=UNDEFINED&ir=false&ic=false&r1=0&c1=6&r2=44&c2=20&attachment=true&gid='));%7Delse%7Balert('Incorrect URL format');%7D
Every time I need to export a Google Sheet I just click on the bookmark and the export is done. I hope this might help you as well.
I am still missing one parameter and this is the possibility to rename the exported PDF.

Update Google Doc Files With Data Pulled From a SpreadSheet Using Doc File Name

I need to assign a membership number to each request I receive from aspiring members of my association.
Aspiring members fill a Google Docs file. When their requests are validated, those files need to be updated with the assigned membership number.
Inside the spreadsheet I have two columns. One contains the membership number and the other contains the ID of the request.
Spreadsheet Screenshot
The doc files are named with the ID of the request as well. The membership numbers should be added in place of the placeholder {membershipnumber} found in the doc files.
Doc File Screenshot
Is anyone able to help?
Thanks a lot for your precious help!
I really have no idea how to accomplish this.
I believe your goal is as follows.
You have Google Document files in the specific folder and have a Google Spreadsheet including the values for updating the Google Document files.
You want to replace the value of {membershipnumber} with the values of column "A" by searching the filename using the value of column "C".
In this case, how about the following sample script?
Sample script:
In this sample, please copy and paste the following script to the script editor of Google Spreadsheet and set the variables. And, save the script.
function myFunction() {
const folderId = "###"; // Please set your folder ID of the folder including the Google Document files.
const sheetName = "Sheet1"; // Please set your sheet name.
const folder = DriveApp.getFolderById(folderId);
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
const obj = sheet.getRange("A2:C" + sheet.getLastRow()).getDisplayValues().reduce((o, [a, , c]) => (o[c] = a.trim(), o), {});
const docs = folder.getFilesByType(MimeType.GOOGLE_DOCS);
while (docs.hasNext()) {
const file = docs.next();
const filename = file.getName().trim();
if (obj[filename]) {
const doc = DocumentApp.openById(file.getId());
doc.getBody().replaceText("{membershipnumber}", obj[filename]);
}
}
}
When this script is run, the Google Document files are updated using the values of column "A" by searching the Document files with the filename retrieved from column "C".
References:
reduce()
getFilesByType(mimeType)
replaceText(searchPattern, replacement)

Script time limit for Google sheet

I need to change some formulas at the same cells at an specific sheet (LISTAFINAL) present in a great number of spreadsheets, these one located at the same folder. But it stops at Google script time limit of 6 minutes, making changes only in 9 spreadsheets, and comes the message: Erro - Exceeded maximum execution time.
My goals:
I would like to know if there's any way to or speed up this process or make changes in a bigger number of spreadsheets or both. Here is the code:
function validacao(){
var folder = DriveApp.getFolderById("FOLDER ID");
var x = folder.getFilesByType(MimeType.GOOGLE_SHEETS);
while (x.hasNext()) {
SpreadsheetApp.open(x.next()).getSheets().forEach(sheet => {
sheet.getRange('LISTAFINAL!F5:F15').activate();
sheet.getRange('LISTAFINAL!F5').setValue('=ALUNO1!$F$167');
sheet.getRange('LISTAFINAL!F6').setValue('=ALUNO2!$F$167');
sheet.getRange('LISTAFINAL!F7').setValue('=ALUNO3!$F$167');
sheet.getRange('LISTAFINAL!F8').setValue('=ALUNO4!$F$167');
sheet.getRange('LISTAFINAL!F9').setValue('=ALUNO5!$F$167');
sheet.getRange('LISTAFINAL!F10').setValue('=ALUNO6!$F$167');
sheet.getRange('LISTAFINAL!F11').setValue('=ALUNO7!$F$167');
sheet.getRange('LISTAFINAL!F12').setValue('=ALUNO8!$F$167');
sheet.getRange('LISTAFINAL!F13').setValue('=ALUNO9!$F$167');
sheet.getRange('LISTAFINAL!F14').setValue('=ALUNO10!$F$167');
sheet.getRange('LISTAFINAL!F15').setValue('=ALUNO11!$F$167');
});
}
}
Explanation:
You iterate over all sheets for every spreadsheet file. Your goal is to just get a single sheet and put the formulas in specific cells. Therefore, you can get rid of the forEach loop.
It is a best practice to work with arrays instead of iteratively using multiple google apps script functions.
For example, in your code you are using getRange and setValue 11 times. If you store the formula values in an array you will be able to store them by using only a single getRange and setValues.
Solution:
function validacao(){
const folder = DriveApp.getFolderById("FOLDER ID");
const x = folder.getFilesByType(MimeType.GOOGLE_SHEETS);
const formulas = Array(11).fill().map((_, i) => [`=ALUNO${i+1}!$F$167`]);
while (x.hasNext()) {
let ss_target = SpreadsheetApp.open(x.next());
let sh = ss_target.getSheetByName("LISTAFINAL");
sh.getRange('F5:F15').setValues(formulas);
}
}

Copy paste data to bottom last row on different worksheet with google sheet scrips

I'm trying to a script to work in which value from a specific range are pasted onto another sheet in a specific range. Problem is that not always the entire range of the input sheet is used and next time the function is used the data is pasted below the previously empty cells, see picture. Anybody any ideas?
function submitData2() {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var database = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Data Logboek");
var source = ss.getSheetByName('Logboek Melding');
var dataToCopy = source.getRange('B2:J11');
var lastRow = database.getLastRow();
database.getRange('\'Logboek melding\'!B2:J11')
.copyTo(SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName("Data Logboek").getRange(lastRow + 1,1)
,SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
}
Considerations
Your copying process seems confused:
You are selecting a range in your database Sheet using A1 notation, but you are referencing another Sheet.
You already have the Data Logboek Sheet saved in the database variable, there is no need to get it again from the SpreadsheetApp.
If the copying direction is source -> database you should call toCopy on a source range not the other way around.
Solution
Using your variable declaration you can translate your copying process to this:
var dataToCopy = source.getRange('A1Notation'); // Source data to copy on database
dataToCopy.copyTo(
database.getRange(lastRow + 1, 1), // Destination
SpreadsheetApp.CopyPasteType.PASTE_VALUES, // Copy Paste Type
false // Transpose
);
Reference
copyTo()

Google Apps Script - convert to CSV

I would like to export a Google Sheet to CSV on form submit. I have searched but the only thing similar does not separate it into different columns once I have converted it: Export spreadsheet or CSV text file from Google Drive Forms using script?
It's a simple sheet with 8 columns only.
Any help appreciated
Once you get the values of a spreadsheet range, you'll end up with a two dimensional array. So to convert it, you'll have to construct a string that joins array array cell elements with a comma and join the rows with a new-line ("\n");
Haven't tested this, but should be something like this.
var range = someSheet.getRange("A2:B" + someSheet.getLastRow());
var vals = range.getValues();
//let's pretend vals is as below
var vals = [["A2","B2"], ["A3", "B3"]];
var csvString = vals.join("\n");
DriveApp.createFile("mycsv.csv", csvString);