Append new CSV data to Google Sheet - csv

How can I append imported CSV data to an existing Google Spreadsheet? Once imported there is an empty row at the bottom, and every subsequent time I run the code I would like it to insert the new CSV data following that empty end row.
Here is my existing code:
function getCSV() {
var fSource = DriveApp.getFolderById('0B2lVvlNIDosoajRRMUwySVBPNVE'); // reports_folder_id = id of folder where csv reports are saved
var fi = fSource.getFilesByName('L661_BOM-CAD_14-12-15.csv'); // latest report file
var ss =SpreadsheetApp.openById('1WEDYfEudYsbkUhHbCxZspEbNXz3cjQIe3JdhnbFmmYA'); // data_sheet_id = id of spreadsheet that holds the data to be updated with new report data
var sd = SpreadsheetApp.getActiveSpreadsheet();
var s = SpreadsheetApp.getActiveSheet();
var target = new Array()
var sSheet = SpreadsheetApp.getActiveSpreadsheet();
sheet = SpreadsheetApp.setActiveSheet(sSheet.getSheets()[0]);
if ( fi.hasNext()) {
var file = fi.next();
var csv = file.getBlob().getDataAsString();
var csvData = CSVToArray(csv); // see below for CSVToArray function
var sheet = ss.getSheets()[0];
s.getRange(+1, 1, csvData.length, csvData[5].length).setValues(csvData);
}
};
function CSVToArray( strData, strDelimiter ){
strDelimiter = (strDelimiter || ";");
var objPattern = new RegExp(
(
// Delimiters.
"(\\" + strDelimiter + "|\\r?\\n|\\r|^)" +
// Quoted fields.
"(?:\"([^\"]*(?:\"\"[^\"]*)*)\"|" +
// Standard fields.
"([^\"\\" + strDelimiter + "\\r\\n]*))"
),
"gi"
);
var arrData = [[]];
var arrMatches = null;
while (arrMatches = objPattern.exec( strData )){
var strMatchedDelimiter = arrMatches[ 1 ];
if (
strMatchedDelimiter.length &&
strMatchedDelimiter !== strDelimiter
){
// Since we have reached a new row of data,
// add an empty row to our data array.
arrData.push( [] );
}
var strMatchedValue;
if (arrMatches[ 2 ]){
strMatchedValue = arrMatches[ 2 ].replace(
new RegExp( "\"\"", "g" ),
"\""
);
} else {
strMatchedValue = arrMatches[ 3 ];
}
arrData[ arrData.length - 1 ].push( strMatchedValue );
}
return( arrData );
}

This can now be simplified using the parseCSV utility. If you pass in the values for your fSource, fi, and ss variables to this amended function it should still work and save having to use your CSVToArray method.
Thanks for the point in the right direction. By default your spreadsheet should load to the first sheet (0) already so the additional 'getActiveSpreadsheet' & getActiveSheets are redundant I think.
function getCSVAndAppend(spreadsheetId, folderId, filename) {
var folder = DriveApp.getFolderById(folderId);
var files = folder.getFilesByName(filename);
var openSpreadsheet = SpreadsheetApp.openById(spreadsheetId);
var activeSheet = SpreadsheetApp.getActiveSheet();
if ( files.hasNext()) {
var file = files.next();
var csv = file.getBlob().getDataAsString();
var csvData = Utilities.parseCsv(csv);
var lastrow = activeSheet.getLastRow();
activeSheet.getRange(lastrow + 1, 1, csvData.length, csvData[0].length).setValues(csvData);
}
}

I managed to fix the issue by adding getLastRow(); command
hopefully this helps someone else out
var lastrow = s.getLastRow();
s.getRange(lastrow + 1, 1, csvData.length, csvData[0].length).setValues(csvData);

Related

Add another row content to the .txt

I just got to work the script to export the content of a row to a .txt and put a =, but now i would like to know how i can add the content of other row to the .txt like i will show on the screenshot.
This is the code that i currently have but i dont properly make to work.
function exporttotxt() {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getActiveSheet();
var range = sheet.getRange('G3:G' + sheet.getLastRow());
var rows = range.getValues().filter(([g]) => g.toString() != "");
var range2 = sheet.getRange('I3:I' + sheet.getLastRow());
var rows2 = range2.getValues().filter(([i]) => i.toString() != "");
var fileName="exported.txt";
var folderName="Videos";
var data = rows.splice(0);
var data2 = rows2.splice(0);
var str = data.map(function(e) {return e.join()}).join("=") + "=" + data2.map(function(e) {return e.join()}).join("\n");
var content = str;
// get list of folders with matching name
var folderList = DriveApp.getFoldersByName(folderName);
if (folderList.hasNext()) {
// found matching folder
var folder = folderList.next();
// search for files with matching name
var fileList = folder.getFilesByName(fileName);
if (fileList.hasNext()) {
// found matching file - append text
var file = fileList.next();
var combinedContent = content;
file.setContent(combinedContent);
}
else {
// file not found - create new
folder.createFile(fileName, content);
}
}
}
I believe your goal as follows.
You want to create a text by merging the values of colums "G" and "I".
In your situation, how about retrieving the values from the columns "G" and "I" by one getValues? By this, the process cost will be lower and the script becomes a bit simple. When this is reflected to your script, it becomes as follows.
From:
var range = sheet.getRange('G3:G' + sheet.getLastRow());
var rows = range.getValues().filter(([g]) => g.toString() != "");
var range2 = sheet.getRange('I3:I' + sheet.getLastRow());
var rows2 = range2.getValues().filter(([i]) => i.toString() != "");
var fileName="exported.txt";
var folderName="Videos";
var data = rows.splice(0);
var data2 = rows2.splice(0);
var str = data.map(function(e) {return e.join()}).join("=") + "=" + data2.map(function(e) {return e.join()}).join("\n");
var content = str;
To:
var range = sheet.getRange('G3:I' + sheet.getLastRow());
var rows = range.getValues().filter(([g, _, i]) => g.toString() != "" && i.toString() != "");
var fileName="exported.txt";
var folderName="Videos";
var data = rows.splice(0);
var str = data.map(([g, _, i]) => `${g}=${i}`).join("\n");
var content = str;

Google Spread Sheet Export CSV in the same folder

I am using the script below, working very well (thanks to Ted Bell).
But I need to adapt it because I need the CSV file saved in the same folder as the spreadsheet.
Could you please help me with this matter?
The code below creates a new folder each time on My Drive.
The CSV is ok regarding its name and its format: with semicolon delimiter.
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var csvMenuEntries = [{
name: "export as csv file",
functionName: "saveAsCSV"
}];
ss.addMenu("CSV Export", csvMenuEntries);
var a1 = ss.getRange("A1").getValue();
var name = "MyCompanyName_"+a1;
ss.rename(name);
};
function saveAsCSV() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ssname = ss.getName();
var sheet = ss.getActiveSheet();
var sheetname = sheet.getSheetName();
//Logger.log("DEBUG: the name of the spreadsheet is "+ssname);//DEBUG
//Logger.log("DEBUG: the sheet name is "+sheetname);// DEBUG
//// create a folder from the name of the spreadsheet
var folder = DriveApp.createFolder(ssname.toLowerCase() + '_' +
sheetname.toLowerCase().replace(/ /g, '_') + '_csv_' + new Date().getTime());
//Logger.log("DEBUG: the folder name is "+folder);//DEBUG
// append ".csv" extension to the sheet name
var fileName = ssname + '_' + sheetname + ".csv";
// convert all available sheet data to csv format
var csvFile = so_4225484202(fileName);
// create a file in the Docs List with the given name and the csv data
folder.createFile(fileName, csvFile);
Browser.msgBox('Files are waiting in a folder named ' + folder.getName());
}
function isValidDate(date) {
return date && Object.prototype.toString.call(date) === "[object Date]" && !isNaN(date);
}
function so_4225484202(filename) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var paramsheet = ss.getSheetByName("Parameters");
var linearray = [];
var rowdata = [];
var csv = "";
var fieldvalue = "";
var param = paramsheet.getRange(2, 2, 2);
var paramValues = param.getValues();
//Logger.log("DEBUG: parameters = "+param.getA1Notation());//DEBUG
var fieldDelimiter = paramValues[0][0];
var textDelimiter = paramValues[1][0];
//Logger.log("DEBUG: field delimiter: "+fieldDelimiter+", text delim:
"+textDelimiter);//DEBUG
var rangeData = sheet.getDataRange();
var lastColumn = rangeData.getLastColumn();
var lastRow = rangeData.getLastRow();
//Logger.log("DEBUG: lastColumn: "+lastColumn+", lastRow: "+lastRow);//DEBUG
// Get array of values in the Data Range
var rangeValues = rangeData.getValues();
// Loop through array and build values for csv
for (i = 0; i < lastRow; i++) {
for (j = 0; j < lastColumn; j++) {
var value = rangeValues[i][j];
var theType = typeof value;
if (theType === "object") {
var testdate = isValidDate(value);
//Logger.log("if typeof is object: testdate: "+testdate);//DEBUG
var testtype = typeof testdate;
if (testtype === "boolean") {
// variable is a boolean
//Logger.log("Its a date");//DEBUG
theType = "date";
} else {
//Logger.log("Its not a date");//DEBUG
}
}
if (theType === "string") {
value = textDelimiter + value + textDelimiter;
}
rowdata.push([value]);
};
//Logger.log("DEBUG: rowdata: "+rowdata);//DEBUG
csv += rowdata.join(fieldDelimiter) + "\n";
var rowdata = [];
};
//Logger.log("DEBUG: csv: "+csv);//DEBUG
return csv;
}
You want to create the CSV file in the same folder of the active Spreadsheet.
You want to achieve this by modifying your script.
If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.
Modification point:
In order to retrieve the folder of the active Spreadsheet, DriveApp.getFileById(ss.getId()).getParents().next() is used for retrieving the folder.
Modified script:
Please modify the function of saveAsCSV() in your script as follows.
From:
var folder = DriveApp.createFolder(ssname.toLowerCase() + '_' + sheetname.toLowerCase().replace(/ /g, '_') + '_csv_' + new Date().getTime());
To:
var folder = DriveApp.getFileById(ss.getId()).getParents().next();
References:
getId()
getFileById()
getParents()
If I misunderstood your question and this was not the direction you want, I apologize.

How to import multiple uniquely named CSV attachments from GMAIL to GOOGLESHEETS

I want to import 3 CSV attachments from a single GMAIL email.
Attachment names are as follows:
- Sales.csv
- Labor.csv
- ServerPerformance.csv
I believe it can be done some how using the following:
var title = attachment.getName();
if (attachment.getContentType() === "text/csv" && title === "Sales.csv") {
but could use some help with proper execution.
Below is the script I'm currently using to import based off of GMAIL Labels and CSV attachment name but it is only importing the first attachment (Sales.csv), so I'd like to have 1 label "South Loop" with 3 separate attachments to be imported from a single email to google sheets.
function SLSalesImportFromGmail() {
//gets first(latest) message with set label
var threads = GmailApp.getUserLabelByName('South Loop').getThreads(0,1);
if (threads && threads.length>0) {
var message = threads[0].getMessages()[0];
var attachment = message.getAttachments()[0];
var title = attachment.getName();
// Is the attachment a CSV file
attachment.setContentTypeFromExtension();
if (attachment.getContentType() === "text/csv" && title === "Sales.csv") {
var ss = SpreadsheetApp.getActive();
var sh = ss.getSheetByName("South Loop Sales");
//parses content of csv to array
var dataString = attachment.getDataAsString();
var csvData = CSVToArray(dataString);
// Remember to clear the content of the sheet before importing new data
sh.clearContents().clearFormats();
//pastes array to sheet
var lastRowValue = sh.getLastRow();
for (var i = 0; i < csvData.length; i++) {
sh.getRange(i+lastRowValue+1, 1, 1, csvData[i].length).setValues(new Array(csvData[i]));
}
if( message.getSubject().indexOf('END OF DAY SALES DETAILS') !== -1) {
SLlogTodaysSales();
}
if (attachment.getContentType() === "text/csv" && title === "Labor.csv") {
var ss = SpreadsheetApp.getActive();
var sh = ss.getSheetByName("South Loop Labor");
//parses content of csv to array
var dataString = attachment.getDataAsString();
var csvData = CSVToArray(dataString);
var range = sh.getRange("A:K");
// Remember to clear the content of the sheet before importing new data
range.clear();
//pastes array to sheet
var lastRowValue = sh.getLastRow();
for (var i = 0; i < csvData.length; i++) {
sh.getRange(i+1, 1, 1, csvData[i].length).setValues(new Array(csvData[i]));
}
if( message.getSubject().indexOf('END OF WEEK LABOR DETAILS') !== -1) {
SLlogWeeksLabor();
}
if (attachment.getContentType() === "text/csv" && title === "ServerPerformance.csv") {
var ss = SpreadsheetApp.getActive();
var sh = ss.getSheetByName("South Loop Server Report");
//parses content of csv to array
var dataString = attachment.getDataAsString();
var csvData = CSVToArray(dataString);
var range = sh.getRange("A:M");
// Remember to clear the content of the sheet before importing new data
range.clear();
//pastes array to sheet
var lastRowValue = sh.getLastRow();
for (var i = 0; i < csvData.length; i++) {
sh.getRange(i+1, 1, 1, csvData[i].length).setValues(new Array(csvData[i]));
}
if( message.getSubject().indexOf('END OF DAY') !== -1) {
SLlogTodaysServers()
}
}
}
}
//marks the Gmail message as read, unstars it and deletes it using Gmail API (Filter sets a star)
message.markRead();
message.unstar();
Gmail.Users.Messages.remove("me", message.getId()); // Added
}
}
//The code formats the code so it can be entered into the Google Script
function CSVToArray( strData, strDelimiter ){
// Check to see if the delimiter is defined. If not,
// then default to comma.
strDelimiter = (strDelimiter || ",");
// Create a regular expression to parse the CSV values.
var objPattern = new RegExp(
(
// Delimiters.
"(\\" + strDelimiter + "|\\r?\\n|\\r|^)" +
// Quoted fields.
"(?:\"([^\"]*(?:\"\"[^\"]*)*)\"|" +
// Standard fields.
"([^\"\\" + strDelimiter + "\\r\\n]*))"
),
"gi"
);
// Create an array to hold our data. Give the array
// a default empty first row.
var arrData = [[]];
// Create an array to hold our individual pattern
// matching groups.
var arrMatches = null;
// Keep looping over the regular expression matches
// until we can no longer find a match.
while (arrMatches = objPattern.exec( strData )){
// Get the delimiter that was found.
var strMatchedDelimiter = arrMatches[ 1 ];
// Check to see if the given delimiter has a length
// (is not the start of string) and if it matches
// field delimiter. If id does not, then we know
// that this delimiter is a row delimiter.
if (
strMatchedDelimiter.length &&
(strMatchedDelimiter != strDelimiter)
){
// Since we have reached a new row of data,
// add an empty row to our data array.
arrData.push( [] );
}
// Now that we have our delimiter out of the way,
// let's check to see which kind of value we
// captured (quoted or unquoted).
if (arrMatches[ 2 ]){
// We found a quoted value. When we capture
// this value, unescape any double quotes.
var strMatchedValue = arrMatches[ 2 ].replace(
new RegExp( "\"\"", "g" ),
"\""
);
} else {
// We found a non-quoted value.
var strMatchedValue = arrMatches[ 3 ];
}
// Now that we have our value string, let's add
// it to the data array.
arrData[ arrData.length - 1 ].push( strMatchedValue );
}
// Return the parsed data.
return( arrData );
var label = GmailApp.getUserLabelByName("South Loop");
label.deleteLabel();
}
function SLlogTodaysSales() {
var todaysSales = SpreadsheetApp.getActive().getRange('South Loop Sales Log!SLSalesImport');
var logSheet = todaysSales.getSheet();
logSheet.appendRow(
todaysSales.getValues()
.reduce(function(a, b) { return a.concat(b); }) // flatten the 2D array to 1D
);
}
function SLlogWeeksLabor() {
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('South Loop Labor Log');
var rg=sh.getRange('SLLaborImport');
var vA=rg.getValues();
sh.getRange(sh.getLastRow()+1,1,vA.length,vA[0].length).setValues(vA);
}
function SLlogTodaysServers() {
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('South Loop Server Log');
var rg=sh.getRange('SLServerReport');
var vA=rg.getValues();
sh.getRange(sh.getLastRow()+1,1,vA.length,vA[0].length).setValues(vA);
}
The issue you have is that you're only looking at the first attachment because of this statement var attachment = message.getAttachments()[0];. Instead, just drop the [0] and loop through all of your attachments.
In an effort to make this clearer, I got rid of a bunch of your code for this example. Please review my notes after, as well.
function SLSalesImportFromGmail() {
var ss = SpreadsheetApp.getActive(); // Get the spreadsheet file once
//gets first(latest) message with set label
var threads = GmailApp.getUserLabelByName('South Loop').getThreads(0,1);
if (threads && threads.length > 0) {
var message = threads[0].getMessages()[0];
// Get all of the attachments and loop through them.
var attachments = message.getAttachments();
for (var i = 0; i < attachments.length; i++) {
var attachment = attachments[i];
var title = attachment.getName();
// Is the attachment a CSV file
attachment.setContentTypeFromExtension();
var table = Utilities.parseCsv(attachment.getDataAsString());
if (attachment.getContentType() === "text/csv") {
// Update the specified sheets
// Clears the sheet of values & formatting and inserts the new table
// using the Apps Script built-in CSV parser.
switch (title) {
case "Sales.csv":
ss.getSheetByName("South Loop Sales").getRange("A:M").clear();
ss.getSheetByName("South Loop Sales").getRange(1, 1, table.length, table[0].length).setValues(table);
break;
case "Labor.csv":
ss.getSheetByName("South Loop Labor").getRange("A:M").clear();
ss.getSheetByName("South Loop Labor").getRange(1, 1, table.length, table[0].length).setValues(table);
break;
case "ServerPerformance.csv":
ss.getSheetByName("South Loop Servers").getRange("A:M").clear();
ss.getSheetByName("South Loop Servers").getRange(1, 1, table.length, table[0].length).setValues(table);
break;
}
}
}
if (message.getSubject().indexOf('END OF DAY') !== -1) {
SLlogTodaysSales();
SLlogTodaysServers();
}
if (message.getSubject().indexOf('END OF WEEK') !== -1) {
SLlogTodaysSales();
SLlogTodaysServers();
SLlogWeeksLabor();
}
// Marks the Gmail message as read, unstars it and deletes it using Gmail API (Filter sets a star)
message.markRead();
message.unstar();
Gmail.Users.Messages.remove("me", message.getId()); // Added
}
}
Notes:
You're using a custom CSVToArray() function to convert the CSV file into an array, but Google already provides a method for this with Utilities.parseCsv(). It should suffice in most cases.
There is no need to call both clearContents() and clearFormats(), because clear() does both in a single call.
I'm aware that you have additional logic (e.g. "END OF DAY" emails & slightly different rules for Labor & ServerPerformance). As mentioned before, I removed all of that to demonstrate how to loop through the attachments. You can use an if or switch statement to include that logic in your script, instead of necessarily using the updateSheet() closure that I wrote.
So looking at your code I don't see you iterating through the attachments.
You only are getting the first attachment and then analyzing that without caring for the others.
var attachment = message.getAttachments()[0];
So instead of doing this, take all the attachments with the getAttachments() and make a for loop to analyze every one of them.
var attachments = message.getAttachments();
for(var i=0; i < attachments.length; i++){
var attachment = attachments[i];
//....
// The rest of your code needs to go inside this for loop
}

Select All CSV then Paste All to Google Sheet - Time Out Issue

First, this code does exactly what I need it to do with one issue, if there is too much data for it to move, Google times out and will end the process. In full honestly/transparency, I'm a total script-code noob, so I might be missing something really simple. From what I can tell, this codes stacks data row by row, and if there are too many rows, this is where my breakdown comes in. Is there a why to just select all data, and paste all data? Thanks for your help!
function importDataCDOP() {
var fSource = DriveApp.getFolderById('FILE PATH');
var fi = fSource.getFilesByName('xxxx.csv');
var ss = SpreadsheetApp.openById('FILE PATH');
if ( fi.hasNext() ) {
var ss1 = SpreadsheetApp.getActiveSpreadsheet();
var first = ss.getSheetByName('NEWDATA');
var file = fi.next();
var csv = file.getBlob().getDataAsString();
var csvData = CSVToArray(csv);
var newsheet = ss.getSheetByName('NEWDATA');
var destSheet = ss.getSheetByName('NEWDATA');
var lastRow = destSheet.getLastRow();
destSheet.insertRowAfter(lastRow);
for ( var i=0, lenCsv=csvData.length; i<lenCsv; i++ ) {
destSheet.getRange(lastRow + i + 1, 1, 1, csvData[i].length).setValues(new Array(csvData[i]));
}
file.setName("OP report-"+(new Date().toString())+".csv");
}
};
function CSVToArray( strData, strDelimiter ) {
strDelimiter = (strDelimiter || ",");
var objPattern = new RegExp(
(
"(\\" + strDelimiter + "|\\r?\\n|\\r|^)" +
"(?:\"([^\"]*(?:\"\"[^\"]*)*)\"|" +
"([^\"\\" + strDelimiter + "\\r\\n]*))"
),
"gi"
);
var arrData = [[]];
var arrMatches = null;
while (arrMatches = objPattern.exec( strData )){
var strMatchedDelimiter = arrMatches[ 1 ];
if (
strMatchedDelimiter.length &&
(strMatchedDelimiter != strDelimiter)
){
arrData.push( [] );
}
if (arrMatches[ 2 ]){
var strMatchedValue = arrMatches[ 2 ].replace(
new RegExp( "\"\"", "g" ),
"\""
);
} else {
var strMatchedValue = arrMatches[ 3 ];
}
arrData[ arrData.length - 1 ].push( strMatchedValue );
}
return( arrData );
};
From your question and comment, I could understand that you want to import the csv data from a file of "xxxx.csv" to the sheet of "NEWDATA" on the spreadsheet of "FILE PATH", and when the large csv data is imported, the elapsed time is over the time limitation of Google Apps Script. I understood that this was your issue. For this situation, how about this modification? Although I'm not sure whether this modification can directly solve your issue, please try to run this.
Modification points :
Retrieve a file object using getFilesByName('xxxx.csv').next(), because the csv file is only one.
var first = ss.getSheetByName('NEWDATA'); and var newsheet = ss.getSheetByName('NEWDATA'); are not used in your script.
Removed them.
In your script, the 2 dimensional array of csv data is imported by every element.
I thought that this may be the main cause of your issue.
In the modified script, import the 2 dimensional array at once.
Modified script :
I modified only importDataCDOP().
function importDataCDOP() {
var fSource = DriveApp.getFolderById('FILE PATH');
var file = fSource.getFilesByName('xxxx.csv').next();
var ss = SpreadsheetApp.openById('FILE PATH');
var csv = file.getBlob().getDataAsString();
var csvData = CSVToArray(csv).filter(String);
var destSheet = ss.getSheetByName('NEWDATA');
destSheet.getRange(destSheet.getLastRow() + 1, 1, csvData.length, csvData[0].length).setValues(csvData);
file.setName("OP report-"+(new Date().toString())+".csv");
};
Note :
I didn't modify CSVToArray().
filter(String) remove the elements with only the line break.
If this modified script was over the limitation of execution time, I would like to propose to use Sheets API.
If I misunderstand your question and the elapsed time of modified script was over the limitation, I'm sorry.

Fine tuning 2 GoogleApp Scripts? GMail to GDrive & GDrive to GSheet

I currently have a GoogleSheet, with 2 GoogleApp Scripts that work more or less how I want them too, but I could use a little help in refining them to get them working perfectly.
I have 1 script that scans through my email, looks for a mail's subject and then pulls it to my Google Drive if it matches.
Script 1: Pull from Gmail to GDrive
function importData() {
var fSource = DriveApp.getFolderById('0B3h9TQiHV_rjR04xTlctb2s2Qms'); // reports_folder_id = id of folder where csv reports are saved
var fi = fSource.getFilesByName('CR Logs this week.csv'); // latest report file
var ss = SpreadsheetApp.openById('1OuEXVjZzPwfdcEW8eIOtNAeS4HJeTn_rw8w5o5Ja-Fo'); // data_sheet_id = id of spreadsheet that holds the data to be updated with new report data
if ( fi.hasNext() ) { // proceed if "CR Logs this week.csv" file exists in the reports folder
var file = fi.next();
var csv = file.getBlob().getDataAsString();
var csvData = CSVToArray(csv); // see below for CSVToArray function
var newsheet = ss.insertSheet('NEWDATA'); // create a 'NEWDATA' sheet to store imported data
// loop through csv data array and insert (append) as rows into 'NEWDATA' sheet
for ( var i=0, lenCsv=csvData.length; i<lenCsv; i++ ) {
newsheet.getRange(i+1, 1, 1, csvData[i].length).setValues(new Array(csvData[i]));
}
/*
** report data is now in 'NEWDATA' sheet in the spreadsheet - process it as needed,
** then delete 'NEWDATA' sheet using ss.deleteSheet(newsheet)
*/
// rename the CR Logs this week.csv file so it is not processed on next scheduled run
file.setName("CR Logs this week.csv-"+(new Date().toString())+".csv");
}
};
// http://www.bennadel.com/blog/1504-Ask-Ben-Parsing-CSV-Strings-With-Javascript-Exec-Regular-Expression-Command.htm
// This will parse a delimited string into an array of
// arrays. The default delimiter is the comma, but this
// can be overriden in the second argument.
function CSVToArray( strData, strDelimiter ) {
// Check to see if the delimiter is defined. If not,
// then default to COMMA.
strDelimiter = (strDelimiter || ",");
// Create a regular expression to parse the CSV values.
var objPattern = new RegExp(
(
// Delimiters.
"(\\" + strDelimiter + "|\\r?\\n|\\r|^)" +
// Quoted fields.
"(?:\"([^\"]*(?:\"\"[^\"]*)*)\"|" +
// Standard fields.
"([^\"\\" + strDelimiter + "\\r\\n]*))"
),
"gi"
);
// Create an array to hold our data. Give the array
// a default empty first row.
var arrData = [[]];
// Create an array to hold our individual pattern
// matching groups.
var arrMatches = null;
// Keep looping over the regular expression matches
// until we can no longer find a match.
while (arrMatches = objPattern.exec( strData )){
// Get the delimiter that was found.
var strMatchedDelimiter = arrMatches[ 1 ];
// Check to see if the given delimiter has a length
// (is not the start of string) and if it matches
// field delimiter. If id does not, then we know
// that this delimiter is a row delimiter.
if (
strMatchedDelimiter.length &&
(strMatchedDelimiter != strDelimiter)
){
// Since we have reached a new row of data,
// add an empty row to our data array.
arrData.push( [] );
}
// Now that we have our delimiter out of the way,
// let's check to see which kind of value we
// captured (quoted or unquoted).
if (arrMatches[ 2 ]){
// We found a quoted value. When we capture
// this value, unescape any double quotes.
var strMatchedValue = arrMatches[ 2 ].replace(
new RegExp( "\"\"", "g" ),
"\""
);
} else {
// We found a non-quoted value.
var strMatchedValue = arrMatches[ 3 ];
}
// Now that we have our value string, let's add
// it to the data array.
arrData[ arrData.length - 1 ].push( strMatchedValue );
}
// Return the parsed data.
return( arrData );
};
The second script then looks through my Google Drive for a matching file name, then imports it to the Google Sheet.
Script 2: Import from GDrive to GSheet
// GLOBALS
//File extension
var fileTypesToExtract = ['csv'];
//Name of the GDrive folder it will be placed
var folderName = 'Reports';
//Name of the label which will be applied after processing the mail message
var labelName = 'ReportToDrive';
function GmailToDrive(){
//query to search mails
var query = 'CR Logs this week';
//filename:csv; //'after:'+formattedDate+
for(var i in fileTypesToExtract){
query += (query == '' ?('filename:'+fileTypesToExtract[i]) : (' OR filename:'+fileTypesToExtract[i]));
}
query = 'in:inbox has:nouserlabels ' + query;
var threads = GmailApp.search(query);
var label = getGmailLabel_(labelName);
var parentFolder;
if(threads.length > 0){
parentFolder = getFolder_(folderName);
}
for(var i in threads){
var mesgs = threads[i].getMessages();
for(var j in mesgs){
//get attachments
var attachments = mesgs[j].getAttachments();
for(var k in attachments){
var attachment = attachments[k];
var isFileType = checkIfCSV_(attachment);
if(!isFileType) continue;
var attachmentBlob = attachment.copyBlob();
var file = DriveApp.createFile(attachmentBlob);
parentFolder.addFile(file);
}
}
threads[i].addLabel(label);
}
}
//This function will get the parent folder in Google drive
function getFolder_(folderName){
var folder;
var fi = DriveApp.getFoldersByName(folderName);
if(fi.hasNext()){
folder = fi.next();
}
else{
folder = DriveApp.createFolder(folderName);
}
return folder;
}
//getDate n days back
// n must be integer
function getDateNDaysBack_(n){
n = parseInt(n);
var today = new Date();
var dateNDaysBack = new Date(today.valueOf() - n*2);
return dateNDaysBack;
}
function getGmailLabel_(name){
var label = GmailApp.getUserLabelByName(name);
if(label == null){
label = GmailApp.createLabel(name);
}
return label;
}
//this function will check for filextension type.
// and return boolean
function checkIfCSV_(attachment){
var fileName = attachment.getName();
var temp = fileName.split('.');
var fileExtension = temp[temp.length-1].toLowerCase();
if(fileTypesToExtract.indexOf(fileExtension) != -1) return true;
else return false;
}
The Goal
I have a piece of software that produces reports in a CSV format, these reports are emailed to me every night at midnight. What I would like to happen is this:
Script 1 pulls CSV from email and imports it to GDrive
Script 2 to import the data to the Google Sheet
Repeat the above on the next night, replacing (and discarding) the previous imported data
Currently, it pulls from my GMail into my GDrive ok. But I can't get it to replace the old data / delete the old data and import the new data.
Would be grand if someone with more experience could help me out!
So, I managed to figure this out by myself in the end.
//function CopyData() {
var source = SpreadsheetApp.openById('xxx');
var sourcesheet = source.getSheetByName('NEWDATA');
var target = SpreadsheetApp.openById('xxx')
var targetsheet = target.getSheetByName('Data');
var targetrange = targetsheet.getRange(2, 1, sourcesheet.getLastRow(), sourcesheet.getLastColumn());
var rangeValues = sourcesheet.getRange(2, 1, sourcesheet.getLastRow(), sourcesheet.getLastColumn()).getValues();
targetrange.setValues(rangeValues);
ss.deleteSheet(newsheet)
This copies the data from NEWDATA, the sheet the Script 2 above creates, and then duplicates it to the sheet Data, replacing whatever is already there.It then deletes the NEWDATA sheet, so that the script can run on the next night.