Parse CSV in Google Spreadsheets - google-apps-script

I'm trying to automatically parse a CSV document into separate cells in Google Spreadsheets. I'm using the script below, however, it just presents the , separated value, whereas, I need those values appear in individual cells. Any ideas?
function importCSVFromWeb() {
var csvUrl = "https://ctrlq.org/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);
}

Related

comma error while importing csv using appscript to google sheets

I am trying to import a csv file to google sheets via google appscript. everything works well except in the last few rows the data is being copied after skipping a row and also it keeps adding more commas to the those empty rows. not sure why. i Have added a test file for reference
https://docs.google.com/spreadsheets/d/1jnzPalCAgO84kxUBrM-aIobIDHu7c99VStJySEyUkKo/edit?usp=sharing
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 ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var header = csvData.shift();
var lastrow = activeSheet.getLastRow();
activeSheet.getRange(lastrow + 1, 1, csvData.length, csvData[0].length).setValues(csvData);
}
}

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

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);
}
}

Importing multiple CSV files to google sheets with Google Script

I am working on a google script to import CSV files from web urls to individual sheets in a google sheet. I would like to have it clear the contents of certain columns before importing the new info. I had had trouble getting the script to clear contents prior to importing. I have also had in include part of one CSV along with another on a sheet. I think I need to add something to the script between CSV files. I also need something added to clear contents prior to importing. I don't want to just clear the sheet because there are formulas that need to remain. I also don't want to use the Google IMPORTDATA function because it is unreliable.
Here is my current script (URLs removed):
function importCSVFromWeb() {
var csvUrl = "http://csvurlhere";
var csvContent = UrlFetchApp.fetch(csvUrl).getContentText();
var csvData = Utilities.parseCsv(csvContent);
var ss = SpreadsheetApp.openByUrl('spreadsheeturlhere');
var sheet = SpreadsheetApp.getActiveSheet();
var ss = sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
var csvUrl = "http://csvurlhere";
var csvContent = UrlFetchApp.fetch(csvUrl).getContentText();
var csvData = Utilities.parseCsv(csvContent);
var sheet = SpreadsheetApp.getActive().getSheetByName('RentPaid');
var ss = sheet.getRange(3, 3, csvData.length, csvData[0].length).setValues(csvData);
var csvUrl = "http://csvurlhere";
var csvContent = UrlFetchApp.fetch(csvUrl).getContentText();
var csvData = Utilities.parseCsv(csvContent);
var sheet = SpreadsheetApp.getActive().getSheetByName('Tenants');
var ss = sheet.getRange(1, 2, csvData.length, csvData[0].length).setValues(csvData);
var csvUrl = "http://csvurlhere";
var csvContent = UrlFetchApp.fetch(csvUrl).getContentText();
var csvData = Utilities.parseCsv(csvContent);
var sheet = SpreadsheetApp.getActive().getSheetByName('Owners');
var ss = sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
}
To clear the contents of a sheet or a range of cells within a sheet, you can use sheet.clearContents() or range.clearContent(), which will remove only values & leave your formatting & formulas in tact.
I note that your line var ss = SpreadsheetApp.openByUrl('spreadsheeturlhere'); does nothing as you subsequently redeclare the ss variable. If the script is bound to a spreadsheet, you don't need this line as calls to getActive() & getActiveSheet() will give you a reference to the host spreadsheet. Your calls to SpreadsheetApp.getActive().getSheetByName() are returning references to the host spreadsheet anyway, not the one you open by URL.
I would also consider changing your function to accept the CSV source URLs, sheet names & cell anchors as parameters so that the code is easier to maintain. e.g.
function importCSVFromWeb(csvUrl, sheetName, dataAnchor) {
/* csvUrl: the CSV source URL
sheetName: the name of the sheet to add the data
dataAnchor: the cell origin for the range.setValues() call as an array
i.e. dataAnchor = [row, col]
*/
var csvContent = UrlFetchApp.fetch(csvUrl).getContentText();
var csvData = Utilities.parseCsv(csvContent);
var ss = SpreadsheetApp.getActive();
// note that you'll need to pass in a name for each sheet,
// including the first one where you used SpreadsheetApp().getActiveSheet() previously
var sheet = ss.getSheetByName(sheetName);
sheet.getRange(dataAnchor[0], dataAnchor[1], csvData.length, csvData[0].length).setValues(csvData);
}
function feedCSVImport(){
var urls_sheets_list = [["csv_source_url_1", "Sheet1", [1,1]],
["csv_source_url_2", "RentPaid", [3,3]],
["csv_source_url_3", "Tenants", [1,2]],
["csv_source_url_4", "Owners", [1,1]]
];
for(var i = 0, lim = url_sheets_list.length; i < lim; ++i){
importCSVFromWeb(url_sheets_list[i][0], url_sheets_list[i][1], url_sheets_list[i][2]);
}
}