Exclude final row during csv file dump into google sheet - google-apps-script

I am extracting a csv file from my Gmail and dumping it into a Google Sheet using this Google App Script.
But the csv file I am receiving has a 'total' towards the end of it, I would like to load all the data except last row from the csv file i.e., n-1
How do I tweak the below code to such that the code excludes last delimited value
function importfromGmail() {
var sheetName = "Stackoverflow"; // Please set the tab name you want to overwrite the data.
var threads = GmailApp.search("label:Stackoverflow"); // Please set here.
var messages = threads[0].getMessages();
var message = messages[messages.length - 1];
var attachment = message.getAttachments()[0];
var data = [];
Logger.log("ContentType: "+attachment.getContentType())
//Logger.log(Utilities.parseCsv(attachment.getDataAsString(), ","));
data = Utilities.parseCsv(attachment.getDataAsString(), ",");
Logger.log(data.length)
if (data.length > 0) {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
Logger.log(SpreadsheetApp.getActiveSpreadsheet().getUrl());
sheet.clearContents().clearFormats();
sheet.getRange(1, 1, data.length, data[0].length).setValues(data);
}
}

In your situation, how about modifying your script as follows?
From:
data = Utilities.parseCsv(attachment.getDataAsString(), ",");
To:
data = Utilities.parseCsv(attachment.getDataAsString(), ",");
data.pop();
By pop(), the last element is removed from data.
Reference:
pop()

Related

Formatting Issues with CSV import to Google Sheets from Gmail

I'm currently importing CSV data from gmail emails automatically using the following script:
function importsearchresultsCSVFromGmail2() {
var threads = GmailApp.search("Scheduled report (********** **** *******)");
var messages = threads[0].getMessages();
var message = messages[messages.length - 1];
var attachment = message.getAttachments()[0];
// Is the attachment a CSV file
attachment.setContentType('text/csv');
//attachment.setContentTypeFromExtension();
if (attachment.getContentType() === "text/csv") {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var sh0 = sheet.getSheetByName("Sheet1")
var csvData = Utilities.parseCsv(attachment.getDataAsString(), ",");
// Remember to clear the content of the sheet before importing new data
sh0.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
GmailApp.markMessageRead(message);
}
}
However, some address fields in the csv are formatted in the entire cell of the csv to be:
Address Layout 1
and some will be shown as "123 New Road, London, NE3 1RD". < These display correctly in the import, however the formatted version above is spread across a number of cells and messes up the original layout of the csv.
Is there a way to ensure the imported cell (that contains the formatted address cell) wont spread across to other cells?
Current CSV File Example
Current Google Sheet Result
Thanks in advance.
Tom
Here is a variant (not so elegant as Yuri solution)
function importCSVFromGoogleDrive() {
var file = DriveApp.getFilesByName("CSV TEST.csv").next();
var csvString = file.getBlob().getDataAsString().replace(/\n/g, '♥').replace(/\r♥/g, '\r\n')
var csvData = Utilities.parseCsv(csvString);
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('mySheet');
sheet.clear();
sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
SpreadsheetApp.flush()
let ranges = SpreadsheetApp.getActive()
.createTextFinder("♥")
.matchEntireCell(false)
.matchCase(true)
.matchFormulaText(false)
.ignoreDiacritics(true)
.findAll();
ranges.forEach(function (range) {
range.setValue(range.getValue().replace(/♥/g,"\n"));
});
}
adapted to your situation
var csvData = Utilities.parseCsv(attachment.getDataAsString().replace(/\n/g, '♥').replace(/\r♥/g, '\r\n'), ",");
sh0.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
SpreadsheetApp.flush()
let ranges = sh0
.createTextFinder("♥")
.matchEntireCell(false)
.matchCase(true)
.matchFormulaText(false)
.ignoreDiacritics(true)
.findAll();
ranges.forEach(function (range) {
range.setValue(range.getValue().replace(/♥/g, "\n"));
});
It would be better if you show your CSV as a text.
I think there are \r and \n inside a quote marks ". You can try to replace them with spaces if you change this line:
var csvData = Utilities.parseCsv(attachment.getDataAsString(), ",");
to this:
var s = attachment.getDataAsString().replace(/"[^"]+?"/, x => x.replace(/[\r\n]+/g, ' '));
var csvData = Utilities.parseCsv(s, ',');
Output:
Update
Here is the variant of about the same function. It does the same thing: replaces \r and \n within quote marks. But it replaces them with the special symbol. And replaces this symbol back to \n after the data is pasted on the sheet:
function get_csv() {
var threads = GmailApp.search("Scheduled report"); // subject
var message = threads[0].getMessages().pop(); // get last message from first thread
var attachment = message.getAttachments()[0]; // first attachment
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getSheetByName("Sheet1");
// get the csv string and replace \n with the symbol ¶
var s = attachment.getDataAsString().replace(/"[^"]+?"/g, x => x.replace(/[\r\n]+/g, '¶'));
var csvData = Utilities.parseCsv(s, ',');
sh.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
sh.getDataRange().createTextFinder('¶').replaceAllWith('\n'); // restore \n inside cells
GmailApp.markMessageRead(message);
}
Result:
Here is the CSV data (not sure if the \r\n are intact after copy and paste):
Activity date & time,Status change,Postcode,Introducer,Marketing source,Assigned user,Lead reference,Lead date,Signed Date,Offered Date,Completed Date,Title,First name,Last name,Lead type,Lead group,Site,Product,"Security Address, if different from above"
01/02/2022,Signed,NE3 1RD,Me,,Me,172312026,15/11/2021,None,None,None,Mr.,John,Smith,Band A,Type 1,Leads.com,Fixed 5,"123 New Road, LONDON, NE3 1RD"
01/02/2022,Signed,NE3 1RD,Me,,Me,172312026,15/11/2021,None,None,None,Mr.,John,Smith,Band A,Type 1,Leads.com,Fixed 5,"123 New Road
LONDON
NE3 1RD"

Apend CSV from gdrive

I am trying to append data from csv saved in google drive to another file in google sheets, I want to ensure that the data gets pasted without the headers. I keep getting an error.
function getCSVAndAppend(spreadsheetId, folderId, filename)
{var folder = DriveApp.getFolderById('1TMFXWDTJpwqTY0JsCefuAean4n9fWIIh');
var files = folder.getFilesByName('Dealers joined data.csv');
var openSpreadsheet = SpreadsheetApp.openById('1E5z7Qd3KRb5geNKlQiYhliYCOtJ0A8ICmZFcUcA1-lI');
var activeSheet = SpreadsheetApp.getActiveSheet();
if ( files.hasNext())\
{var file = files.next();
var csv = file.getBlob().getDataAsString();
var csvData = Utilities.parseCsv(csv);
var csvDataNoHeader = csvData.splice(1,csvData.length-1)
var lastrow = activeSheet.getLastRow();
activeSheet.getRange(lastrow + 1, 1, csvData.length, csvData[0].length).setValues(csvData);
}
}
It's possible that there are other issues as noted by Yuri. But this splice looks incorrect to me
var csvDataNoHeader = csvData.splice(1,csvData.length-1)
I think the 1 should be zero and the other parameter should be 1 but it might actually be easier just to use shift to remove the first row. I think csvData is a 2d array.

How to show ONLY filtered data when publishing the sheet?

I am importing some data (CSV file from URL). And I am using this script to update data whenever the source gets updated :
function importCSVFromWeb() {
// Provide the full URL of the CSV file.
var csvUrl = "https://covid19.who.int/WHO-COVID-19-global-table-data.csv";
var csvContent = UrlFetchApp.fetch(csvUrl).getContentText();
var csvData = Utilities.parseCsv(csvContent);
var sheet = SpreadsheetApp.getActiveSheet();
sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
}
After I filter my data in google spreadsheets and every time the source gets updated, the filtered data are not filtered anymore!. I want to publish the sheet with filtered data only
My question is: After importing and filtering the data, How can I keep my filter on the data even when the source gets updated?
I believe your current situation and your goal as follows.
You have a Spreadsheet installed the basic filter.
When you update the Spreadsheet by your script, you want to continue to use the existing basic filter.
In this case, how about reinstall the basic filter by copying the existing basic filter? When this is reflected to your script, it becomes as follows.
Modified script:
function importCSVFromWeb() {
// Provide the full URL of the CSV file.
var csvUrl = "https://covid19.who.int/WHO-COVID-19-global-table-data.csv";
var csvContent = UrlFetchApp.fetch(csvUrl).getContentText();
var csvData = Utilities.parseCsv(csvContent);
var sheet = SpreadsheetApp.getActiveSheet();
// --- I added below script.
var filter = sheet.getFilter();
var range = filter.getRange();
var criteria = [];
var start = range.getColumn();
var end = start + range.getNumColumns() - 1;
for (var i = start; i <= end; i++) {
var criterion = filter.getColumnFilterCriteria(i);
if (criterion) criteria.push({col: i, c: criterion.copy()});
}
filter.remove();
// ---
sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
// And, I added below script.
criteria.forEach(({col, c}) => range.createFilter().setColumnFilterCriteria(col, c));
}
References:
getFilter() of Class Sheet
createFilter() of Class Range

Change Google Apps Script from printing array from active cell to specific sheet and range

I'm trying to figure out how to tell the script to print to a specific sheet named 'Creative' and starting in cell B2. Instead of printing to The code, I'm using the code below. Thanks so much for any help you can offer.
function getFileArray(folderId){
var folder = DriveApp.getFolderById(folderId);
var files = folder.getFiles();
var fileList = [];
//Loop though files and add names and urls to the array
while (files.hasNext()){
var file = files.next();
var fileName = file.getName();
var fileUrl = file.getUrl();
fileList = fileList.concat([[fileName, fileUrl]]);
}
//See returned fileList in a log
//Logger.log( fileList ) //Preview Returned Array
return fileList
}
//Prints any 2D array to a range that starts with the selected cell
function printArrayToSelection(twoDimArr){
var firstCell = SS.getActiveCell();
var lastCell = firstCell.offset(twoDimArr.length - 1, twoDimArr[0].length - 1);
var destinationRange = SS.getActiveSheet().getRange(
firstCell.getA1Notation() + ':' + lastCell.getA1Notation());
destinationRange.setValues(twoDimArr);
}
//Print the actual data
function printFileArray(){
printArrayToSelection(getFileArray('FOLDERIDHERE'));
}
To specify the sheet for the destination range, you can use the getSheetByName method and pass "Creative" as an argument.
To get the destination range, I would recommend using the getRange method and passing the row, column, number of rows, and number of columns as arguments. For your case, this would be 2, 2, twoDimArr.length, twoDimArr[0].length
The documentation for this method can be found here:
https://developers.google.com/apps-script/reference/spreadsheet/sheet#getRange(Integer,Integer,Integer,Integer)
function printArrayToSelection(twoDimArr){
var firstCell = SS.getActiveCell();
var lastCell = firstCell.offset(twoDimArr.length - 1, twoDimArr[0].length - 1);
var destinationRange = SS.getSheetByName("Creative").getRange(2, 2, twoDimArr.length, twoDimArr[0].length);
destinationRange.setValues(twoDimArr);
}

Trouble Uncompressing Zip and then parsing CSV with Google Apps Script

Trying to create a Google Apps Script that reads emails from a specific email address and copy the contents of a CSV file into a Google sheet.
Problem is sometimes the files come in as zip attachments. I'm trying to work logic into the script to uncompress the zip if it's a zip attachment and then post the data to the Google sheet.
Currently getting the following error message: Cannot find function getDataAsString in object Blob.
Any ideas / recommendations for getting this to work with potential zip files would be great.
You can find my full code below:
function myFunction() {
var threads = GmailApp.search("from:testemail#example.com");
var message = threads[0].getMessages()[0];
var attachment = message.getAttachments()[0];
Logger.log(attachment.getContentType());
// Is the attachment a CSV file
if (attachment.getContentType() === "text/csv") {
var sheet = SpreadsheetApp.getActiveSheet();
var csvData = Utilities.parseCsv(attachment.getDataAsString(), ",");
Logger.log("Found a CSV file");
// Remember to clear the content of the sheet before importing new data
sheet.clearContents().clearFormats();
sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
}
if (attachment.getContentType() === "application/zip") {
var sheet = SpreadsheetApp.getActiveSheet();
var files = Utilities.unzip(attachment);
Logger.log(files);
var newDriveFile = DriveApp.createFile(files[0]);
var csvData = Utilities.parseCsv(files.getDataAsString(), ",");
Logger.log("Found a ZIP file");
// Remember to clear the content of the sheet before importing new data
sheet.clearContents().clearFormats();
sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
}
}
Utilities.unzip will return array of blobs. So you need to refer the particular blob inside the array of blobs. Just modify the below code snippet.
var files = Utilities.unzip(attachment)[0];
Also, it is safe to mention the charset so that special characters are displayed properly.
var csvData = Utilities.parseCsv(attachment.getDataAsString('ISO-8859-1'), ",");
Entire Function:
function exportData() {
var threads = GmailApp.search("from:testemail#example.com");
var message = threads[0].getMessages()[0];
var attachment = message.getAttachments()[0];
Logger.log(attachment.getContentType());
// Is the attachment a CSV file
if (attachment.getContentType() === "text/csv") {
var sheet = SpreadsheetApp.getActiveSheet();
var csvData = Utilities.parseCsv(attachment.getDataAsString('ISO-8859-1'), ",");
Logger.log("Found a CSV file");
// Remember to clear the content of the sheet before importing new data
sheet.clearContents().clearFormats();
sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
}
if (attachment.getContentType() === "application/zip") {
var sheet = SpreadsheetApp.getActiveSheet();
var files = Utilities.unzip(attachment)[0];
var csvData = Utilities.parseCsv(files.getDataAsString('ISO-8859-1'), ",");
Logger.log("Found a ZIP file");
// Remember to clear the content of the sheet before importing new data
sheet.clearContents().clearFormats();
sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
}
}