GetRange() give a width error after 3000 rows - csv

the getrange code give the error
Incorrect Range width, was 1 but should be 5
The CSV file has 8127 rows and when I broke up the file in 8 different files each containing 1000 rows and processed them separatly they all completed without any errors. But once i process a file greater than 3000+ rows it gets the above error message.
below is the get range code
ss.getRange(lastrow + 1,1,csvData.length,csvData[0].length).setValues(csvData);
I have also tried this but this gets an error stating exceeded maximum execution time:
for (var i = 0; i < csvData.length; i++) {
ss.getRange(i + 1,1,1,csvData[i].length).setValues(new Array(csvData[i]));
}
The CSV file is 2D.
Below is the full code:
Function getCSV() {
var fSource = DriveApp.getFolderById('0B2lVvlNIDosoajRRMUwySVBPNVE'); //reports_folder_id = id of folder where csv reports are saved
var date= Utilities.formatDate(new Date(), "GMT", "dd-MM-yy");
var fi = fSource.getFilesByName('L661_BOM-CAD_07-01-16.csv');
// latest report file
var ss = SpreadsheetApp.openById('1V8YG8lyNZiTllEPHENcnabYRLDPCK6mHGUyAyNhW0Is').getSheet s()[0]; // data_sheet_id = id of spreadsheet that holds the data to be updated with new report data Sheet will be opened server side.
ss.getName() == "Sheet1"
if ( fi.hasNext()) { // proceed if "report.csv" file exists in the reports folder
var file = fi.next();
//file.setName('L661_BOM-CAD_'+ date +'(EXPORTED)'+'.csv');
var csv = file.getBlob().getDataAsString();
var csvData = CSVToArray(csv);
Logger.log('csvData[0].length: ' + csvData[0].length + ' csvData.length:' + csvData.length);
var lastrow = ss.getLastRow();
for (var i = 0; i < csvData.length; i++) {
ss.getRange(i + 1,1,1,csvData[i].length).setValues(new Array(csvData[i]));
}
}
if( ss.getName() == "Sheet1" ) { //checks that we're on the correct sheet
var r= ss.getRange('A1');
if( r.getColumn() == 1 ) { //checks the column
var nextCell = r.offset(0, 5);
if( nextCell.getValue() === '' ) //is empty?
var date = new Date();
var date= Utilities.formatDate(new Date(), "GMT", "dd-MM-yy");
nextCell.setValue(date); //enters the date in F1 in dd/mm/yyyy format
};
};
};
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 )){
// 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( [] );
}
var strMatchedValue;
// 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.
strMatchedValue = arrMatches[ 2 ].replace(
new RegExp( "\"\"", "g" ),
"\""
);
} else {
// We found a non-quoted value.
strMatchedValue = arrMatches[ 3 ];
}
// Now that we have our value string, let's add
// it to the data array.
arrData[ arrData.length - 1 ].push( strMatchedValue );
Logger.log('arrData[0].length: ' + arrData[0].length);
}
// Return the parsed data.
return( arrData );
}

Check the value of csvData[0].length again. It says length should be 5 but it gives 1.
Since it has more than 3000 records, it will exceed maximum execution time. setting values will take much time when it is on a loop. What you want to do is first get the values to an array and set them once later.
var myvalueArray = [];
for (var i = 0; i < csvData.length; i++) {
// do not set value here
//ss.getRange(i + 1,1,1,csvData[i].length).setValues(new Array(csvData[i]));
//push your values to an array
myvalueArray.push(csvData[i]);
}
once you push your values to defined array, set them once on your range.
ss.getRange(1,1,1,csvData[i].length).setValues(myvalueArray);

Related

Is there a way to stop my google script from wrapping text into a new cell? [duplicate]

I've pieced together this code from various google searches that will pull an e-mail's CSV attachment if the e-mail has a specific label.
function importCSVFromGmail() {
//gets first(latest) message with set label
var threads = GmailApp.getUserLabelByName('Dashboard Updates').getThreads(0,1);
var message = threads[0].getMessages()[0];
var attachment = message.getAttachments()[0];
// Is the attachment a CSV file
if (attachment.getContentType() === "text/csv") {
var ss = SpreadsheetApp.getActive();
var sh = ss.getSheetByName("Monthly_Detail_Instantis");
//parses content of csv to array
var dataString = attachment.getDataAsString();
var escapedString = dataString.replace(/(?=["'])(?:"[^"\\]*(?:\\[\s\S][^"\\]*)*"|'[^'\\]\r\n(?:\\[\s\S][^'\\]\r\n)*')/g, '\\r\\n');
var csvData = Utilities.parseCsv(escapedString);
// Remember to clear the content of the sheet before importing new data
sh.clearContents().clearFormats();
//pastes array to sheet
sh.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
}
//marks the Gmail message as read and unstars it (Filter sets a star)
message.markRead();
message.unstar();
}
The script runs fine, however I am running into issues with cells that had values with commas or quotes. For example, if a cell has the following:
1,000,000
or
Google "Apps" Script
It will return to following, respectively.
\r\n
\r\n\r\n\r\n
I'm certain it has to do with the Regex used, however I am not certain how to adjust for the above. Any help with this would be greatly appreciated.
I was able to use the original code (used in question) and replace the escaping and Utilities.parseCsv with code from this link. This will properly import CSVs even if cells include quotes and commas:
https://productforums.google.com/forum/#!topic/docs/nhXjrl8JIek
Here is my final code:
function importCSVFromGmail() {
//gets first(latest) message with set label
var threads = GmailApp.getUserLabelByName('Dashboard Updates').getThreads(0,1);
var message = threads[0].getMessages()[0];
var attachment = message.getAttachments()[0];
// Is the attachment a CSV file
if (attachment.getContentType() === "text/csv") {
var ss = SpreadsheetApp.getActive();
var sh = ss.getSheetByName("Monthly_Detail_Instantis");
//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]));
}
}
//marks the Gmail message as read and unstars it (Filter sets a star)
message.markRead();
message.unstar();
}
//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 );
}

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
}

Importing csv file to google sheets using script

i am faced with the below problem. I am going to be presented with a .csv file that will contain the following fields:
ItemID Date Source name Title URL Created ItemSourceType
However i won't need all of the fields but i will need to import this into a pre-defined google sheets template, which looks like the below:
Date Writer Status Geog/Area/Product Source Title Note
Again not all of the columns will need to be populated, and so the final solution should look like this.
Date Writer Status Geog/Area/Product Source Title Note
Today() NULL NULL Null Site Title-(hyperlinked with URL) Null
i have put together the following code - some of this has been testing and trying to split out a CSV, and i've not yet attempted to add the hyperlinked field.
function addData() {
var fSource = DriveApp.getFolderById('138ZRbesgDkKHOROm4izD22oaXoanvsyJ'); // reports_folder_id = id of folder where csv reports are saved
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 12; // First row of data to process
var numRows = 2; // Number of rows to process
var fSource = DriveApp.getFolderById('138ZRbesgDkKHOROm4izD22oaXoanvsyJ'); // reports_folder_id = id of folder where csv reports are saved
var fi = fSource.getFilesByName('data.csv'); // latest report file
var ss = SpreadsheetApp.openById('1wBawJzQ3eAhyjCuetAFg7uUUrum6CDImBcVcxaZ9j84'); // data_sheet_id = id of spreadsheet that holds the data to be updated with new report data
if ( fi.hasNext() ) { // proceed if "report.csv" file exists in the reports folder
var file = fi.next();
var csv = file.getBlob().getDataAsString();
var csvData = CSVToArray(csv);
for ( var i=1, lenCsv=csvData.length; i<lenCsv; i++ ) {
sheet.getRange(i+1, 1, 1, csvData[i].length).setValues(new Array(csvData[i]));
}
}
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 );
};
// Fetch the range of cells A2:G3
var dataRange = sheet.getRange(startRow, 1, numRows,8)//sheet.getRange(startRow, 1, numRows, 8)
var data = dataRange.getValues();
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var ItemID = row[0]
var Date = row[1]
var SourceName = row[2]
var Title = row[3]
var URL = row[4]
var Created = row[5]
var ItemSourceType = row[6]
sheet.getRange(i+1, 1, 1, csvData[i].length).setValues(new Array(csvData[i]));
}
var correctFormat = ItemID + ", " + Date + ", " + SourceName + ", " + Title + ", " + URL + ", " + Created + ", " + ItemSourceType;
Logger.log(correctFormat)
}
If anyone is able to help point me in the right direction it would be greatly appreciated.
The part of this that i am struggling with is using the Array to populate the spreadsheet with the fields in the correct order, I have put the array below.
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 );
};
It seems like this site (https://ctrlq.org/code/20279-import-csv-into-google-spreadsheet) does include several ways to import a CSV into a google spreadsheet.
For instance for importing from google drive you can do:
function importCSVFromGoogleDrive() {
var file = DriveApp.getFilesByName("data.csv").next();
var csvData = Utilities.parseCsv(file.getBlob().getDataAsString());
var sheet = SpreadsheetApp.getActiveSheet();
sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
}
After that you will need to filter the data you want, but i guess it is easier to do that once you have imported the data from the csv.

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.

Google Apps Script close UI App after execution

I have a script that imports data from a csv file after inserting the name of the file via a UI. It all works 100%, the file is located and the data is imported as expected. However, the app does not close and the pop-up UI remains active on the screen.
My script is as follows:
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var menuEntries = [
{name: "Import Employee Base Data", functionName: "importFromBaseCSV"},
];
ss.addMenu("User Functions", menuEntries);
}
//IMPORT BASE DATA FROM CSV
function importFromBaseCSV() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var importBaseDataApp = UiApp.createApplication().setTitle('Import BASE Data').setHeight(120).setWidth(350);
var importBaseDataGrid = importBaseDataApp.createGrid(3, 2);
importBaseDataGrid.setWidget(0, 0, importBaseDataApp.createLabel('Enter the File Date: '));
importBaseDataGrid.setWidget(0, 1, importBaseDataApp.createTextBox().setName('baseDataFilename').setFocus(true).setWidth(150));
importBaseDataGrid.setWidget(1, 0, importBaseDataApp.createLabel('e.g. 23092013'));
importBaseDataGrid.setWidget(2, 0, importBaseDataApp.createLabel(''));
var importBaseDataPanel = importBaseDataApp.createVerticalPanel();
importBaseDataPanel.add(importBaseDataGrid);
var importButton = importBaseDataApp.createButton('Import');
var importHandler = importBaseDataApp.createServerHandler('importBaseData');
importHandler.addCallbackElement(importBaseDataGrid);
importButton.addClickHandler(importHandler);
importBaseDataPanel.add(importButton);
importBaseDataApp.add(importBaseDataPanel);
ss.show(importBaseDataApp);
}
function importBaseData(e){
var fileName = "C BS BASE " + e.parameter.baseDataFilename + ".csv";
var files = DocsList.getFiles();
var csvFile = "";
for (var i = 0; i < files.length; i++) {
if (files[i].getName() == fileName) {
csvFile = files[i].getContentAsString();
break;
}
}
var csvData = CSVToArray(csvFile, ",");
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Imported Base Data");
for (var i = 0; i < csvData.length; i++) {
sheet.getRange(i+1, 1, 1, csvData[i].length).setValues(new Array(csvData[i]));
}
}
// 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 );
}
SpreadsheetApp.getActiveSpreadsheet().toast("...Completed", "Import Employee Base Data:", 3);
// Return the parsed data.
return( arrData );
var importBaseDataApp = UiApp.getActiveApplication();
importBaseDataApp.close();
return importBaseDataApp;
}
Can anyone help?
I just looked at it quickly, but try this. I moved the "Toast" and "Close" into the function that is called by the clickHandler. You want to control the Ui's in their calling function, its much smoother. Sometimes you might get lucky and they close or update calling them in another called function.
function importBaseData(e){
var fileName = "C BS BASE " + e.parameter.baseDataFilename + ".csv";
var files = DocsList.getFiles();
var csvFile = "";
for (var i = 0; i < files.length; i++) {
if (files[i].getName() == fileName) {
csvFile = files[i].getContentAsString();
break;
}
}
var csvData = CSVToArray(csvFile, ",");
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Imported Base Data");
for (var i = 0; i < csvData.length; i++) {
sheet.getRange(i+1, 1, 1, csvData[i].length).setValues(new Array(csvData[i]));
}
SpreadsheetApp.getActiveSpreadsheet().toast("...Completed", "Import Employee Base Data:", 3);
var importBaseDataApp = UiApp.getActiveApplication();
importBaseDataApp.close();
return importBaseDataApp;
}
// 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 );
}