I am hitting the Google Scripts 6-minute timeout. The script is running through quite a few folders and subfolders. I am hoping that there is either (or both):
A way to optimize the script to more efficiently/intelligently run through the dataset/iterators?
A way to use a getContinuationToken()
Any help would be much appreciated!
I have tried to limit the number of folders/subfolders the script runs through. Even on a 'minimal' run, it times out. And FYI, my goal is to:
make a copy of files that are NOT owned by 'me'...
change the name of the original file (that was not owned by me) to be 'delete'
Here is the code:
FOLDERS = ["0B4FiuEqe8ftGb2lSbjJzakJDNWs"]; /*, "0B4FiuEqe8ftGN2YxZFU5RlhMSDQ", "0B4FiuEqe8ftGN2YxZFU5RlhMSDQ", "1D_1u_KwcLOsBuKyQ7NCsKDd8DB5JwOn6"];*/
function copyNonOwnedFiles() {
var arr = FOLDERS
for (var j = 0; j < arr.length; j++) {
var folderTOP = DriveApp.getFolderById(arr[j]);
var folders = folderTOP.getFolders();
var me = Session.getActiveUser().getEmail();
//RUN #1 = this runs through all of the subfolders
//iterator 1
while (folders.hasNext()) {
var folder = folders.next();
//get all files within these folders
var files = folder.getFiles();
//iterator 2
while (files.hasNext()) {
var file = files.next();
var Owner = file.getOwner().getEmail();
if( Owner !== me ){
var name = file.getName();
file.makeCopy(name);
file.setName('delete');
}
}
}
//RUN #2 = this runs through the parent folder
var files2 = folderTOP.getFiles();
//iterator 2
while (files2.hasNext()) {
var file2 = files2.next();
var Owner = file2.getOwner().getEmail();
if( Owner !== me ){
var name2 = file2.getName();
file2.makeCopy(name2);
file2.setName('delete');
}
}
}
}
Try this:
This script will find the files owned by the active user, in the folders with the listed ids and display them on a modeless dialog. This script will probably need to utilize lock service for multiple simultaneous users.
var myFiles=[];
var ids=["0B4FiuEqe8ftGb2lSbjJzakJDNWs", "0B4FiuEqe8ftGN2YxZFU5RlhMSDQ", "0B4FiuEqe8ftGN2YxZFU5RlhMSDQ", "1D_1u_KwcLOsBuKyQ7NCsKDd8DB5JwOn6"];
var me='';
function getMyFiles() {
myFiles=[];
me=Session.getActiveUser().getEmail();
for(var i=0;i<ids.length;i++) {
getFnF(DriveApp.getFolderById(ids[i]));
}
var html="<style>th,td{border:1px solid black;}</style><table><tr><th>Item</th><th>Name</th><th>Url</th></tr>";
for(var i=0;i<myFiles.length;i++) {
html+=Utilities.formatString('<tr><td>%s</td><td>%s</td><td>Link</td></tr>',i+1,myFiles[i].name,myFiles[i].url);
}
html+='</table><input type="button" value="Close" onClick="google.script.host.close();" />';
var userInterface=HtmlService.createHtmlOutput(html);
var title=Utilities.formatString('Files Owned by: %s',me);
SpreadsheetApp.getUi().showModelessDialog(userInterface, title)
}
function getFnF(folder) {
var folder= folder || DriveApp.getRootFolder();
var files=folder.getFiles();
while(files.hasNext()) {
var file=files.next();
if(file.getOwner().getEmail()==me) {
myFiles.push({name:file.getName(),url:file.getUrl()});
}
}
var subfolders=folder.getFolders()
while(subfolders.hasNext()) {
var subfolder=subfolders.next();
getFnF(subfolder);
}
}
for anyone who has this same question or a similar one... I found that it was much faster/easier/less resource intensive to use a search than a file iterator
dataSheetName = "List";
function onOpen(){
var ui = SpreadsheetApp.getUi();
ui.createMenu('Custom Menu')
.addItem('List Files', 'ListFiles')
.addSeparator()
.addToUi();
}
function ListFiles() {
var sheet = SpreadsheetApp.getActive();
var dataSheet = sheet.getSheetByName(dataSheetName);
// Clear Sheet
var lastRow = dataSheet.getLastRow();
if (lastRow > 0) {
dataSheet.getRange(2, 1, lastRow, dataSheet.getLastColumn()).clearContent();
}
dataSheet.getRange("E2").setValue("Process Started at: " + new Date());
Logger.log("Start: " + new Date());
// var row = ['File Name', 'File Id'];
var row = ['File Name', 'File Id'];
var data = [];
data.push(row);
// Find files modified in the last 24 hours
var totalDays = 30;
var today = new Date();
var oneDayAgo = new Date(today.getTime() - totalDays * 24 * 60 * 60 * 1000);
var startTime = oneDayAgo.toISOString();
// The magic search expression
var search = '(trashed = false) and (modifiedDate > "' + startTime + '") and not (title contains \'DELETE\') and not (\'me\' in owners) ';
// var search = "(mimeType='image/jpeg') and not (title contains 'DELETE') ";
// var search = " not ('me' in owners) and not (title contains 'DELETE') ";
// var search = " not ('me' in owners) ";
//var search = 'sharedWithMe';
// 'me' in owners
var i = 1;
var files = DriveApp.searchFiles(search);
Logger.log("2: " + new Date());
dataSheet.getRange("E3").setValue("Search Completed at: " + new Date());
// while (files.hasNext() && (i < 10000) {
while (files.hasNext() ) {
var file = files.next();
try {
// data.push([file.getName(),file.getId()]);
data.push([file.getName(), file.getId()]);
}
catch (e) {
Logger.log(file.getName());
}
// i += i;
}
// Write data
var dataRange = dataSheet.getRange(1, 1, data.length, row.length);
dataRange.setValues(data);
Logger.log("3: " + new Date());
dataSheet.getRange("E4").setValue("List Completed at: " + new Date());
}
Related
I am new to Google AppScripts, and really struggling with achieving my end goal. The following code get's me very close, but I am wondering if anyone can please point me in a direction that enables me to do the following:
Extract .xlsx file from gmail that is received daily
Transfer the contents of the .xlsx file to an already existing Google sheet
Any advice would be hugely appreciated.
James
// GLOBALS
//Array of file extension which you would like to extract to Drive
var fileTypesToExtract = ['jpg', 'tif', 'png', 'gif', 'bmp', 'svg'];
//Name of the folder in google drive i which files will be put
var folderName = 'GmailToDrive';
//Name of the label which will be applied after processing the mail message
var labelName = 'GmailToDrive';
function GmailToDrive(){
//build query to search emails
var query = '';
//filename:jpg OR filename:tif OR filename:gif OR fileName:png OR filename:bmp OR filename:svg'; //'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);
}
var root = DriveApp.getRootFolder();
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 isDefinedType = checkIfDefinedType_(attachment);
if(!isDefinedType) continue;
var attachmentBlob = attachment.copyBlob();
var file = DriveApp.createFile(attachmentBlob);
parentFolder.addFile(file);
root.removeFile(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 date = new Date();
date.setDate(date.getDate() - n);
return Utilities.formatDate(date, Session.getScriptTimeZone(), 'yyyy/MM/dd');
}
function getGmailLabel_(name){
var label = GmailApp.getUserLabelByName(name);
if(!label){
label = GmailApp.createLabel(name);
}
return label;
}
//this function will check for filextension type.
// and return boolean
function checkIfDefinedType_(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;
}
That's the codes I'm using for getting attachments from gmail to existing spreadsheet.
By setting up time driven trigger.
In order to make this function run faster. set the label name and the thread limites
function attachfromGmail(attachmentname, destsheet_id, destsheetname, label_name, all_or_part) {
const folder = DriveApp.getFolderById("xasdawfes2342ke");
const labels = GmailApp.getUserLabelByName(label_name).getThreads(0, 10);
const threads = GmailApp.getMessagesForThreads(labels);
const today_date = Utilities.formatDate(new Date(), "GMT-6", "MM/dd/yyyy");
var fileid_FromGmail = "";
threads.forEach(threads => {
threads.filter(messge => {
if (Utilities.formatDate(messge.getDate(), "GMT-6", "MM/dd/yyyy") == today_date) {
messge.getAttachments().filter(attachments => {
if (attachments.getName() == attachmentname && messge.isUnread() === true) {
messge.markRead();
const blob = attachments.copyBlob();
var file_FromGmail = Drive.Files.insert(
{ title: attachmentname, parents: [{ "id": folder.getId() }] },
blob,
{ convert: true }
);
fileid_FromGmail = file_FromGmail.id;
}
})
}
})
})
const created_file = SpreadsheetApp.openById(fileid_FromGmail);
const values = created_file.getDataRange().getDisplayValues();
const destfiles_sheet = SpreadsheetApp.openById(destsheet_id).getSheetByName(destsheetname);
if (all_or_part === 'all' && values != undefined) {
destfiles_sheet.clear();
destfiles_sheet.getRange(1, 1, created_file.getLastRow(), created_file.getLastColumn()).setValues(values);
} else if (values.length === 1 && values.toString() != 'No Data Available' || values.length > 1) {
values.shift()
destfiles_sheet.getRange(destfiles_sheet.getLastRow() + 1, 1, values.length, values[0].length).setValues(values);
}
//delete created file
DriveApp.getFileById(fileid_FromGmail).setTrashed(true);
}
It works well, but I'm trying to get a better way to do the job. Instead of insert a new file and delete. I know we can use csv parse function to get the data. but I can not fix the leading 0 issue in the csv file.
Then I'm trying to use XML file to transfer data, still working on it.
I will update this post if I get a better solution.
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.
Here are my 2 spreadsheets:
Gsheet1: Googlesheet for replication (only employee # and employee name would change)
Gsheet2: Config sheet (contains the employee #, employee name, replication status, pubHTML link) that would feed employee # and employee name on Gsheet1
So I have this code that have these functionalities below:
Replicate Gsheet1 depending on the number of employees (I currently have 800+ employees) on Gsheet2 and dump it to a google drive folder.
after replication, will set a "completed" replication status to Gsheet2.
Change the revision properties of the replicated sheet and make it published to web.
Get the link of the published web (pubhtml) and put it on Gsheet2 pubHTML link column.
What happens is when I try to logger.log the results of this code below assuming that I have 2 records on my Gsheet2, it loops three times, the first and third record in loop are the same.
var TemplatesFromDrive = DriveApp.getFolderById(SpreadsheetApp.getActive().getSheetByName("Master Config").getRange("B2").getValue()).getFiles();
while (TemplatesFromDrive.hasNext()) {
var File = TemplatesFromDrive.next();
Logger.log(File.getName());
I was thinking if it's because of the Spreadsheet.flush() that I'm missing. Where is the best place where I can put it on my code so my loop will work properly? Below is my full code.
function replicateCards() {
var ss = SpreadsheetApp.openById('Gsheet2-xxxx');
var copyCard = SpreadsheetApp.openById('Gsheet1-xxxx');
var getID = DriveApp.getFileById(copyCard.getId())
var card = copyCard.getSheetByName("Card");
var mastersheet = ss.getSheetByName("Mastersheet");
var employeeNumber2 = ss.getRange("A2:A").getValues;
var getLastRow = mastersheet.getLastRow();
var destinationFolder = DriveApp.getFolderById('googledrivefolder-xxx');
var changeColorToGrayList = card.getRangeList(['C7', 'E7', 'G7', 'I7', 'K7', 'M7', 'O7', 'Q7',
'C9', 'E9', 'G9', 'I9', 'K9', 'M9', 'O9', 'Q9',
'C11', 'E11', 'G11', 'I11', 'K11', 'M11', 'O11', 'Q11']);
var setValueToZero = card.getRangeList(['C8', 'E8', 'G8', 'I8', 'K8', 'M8', 'O8', 'Q8',
'C10', 'E10', 'G10', 'I10', 'K10', 'M10', 'O10', 'Q10',
'C12', 'E12', 'G12', 'I12', 'K12', 'M12', 'O12', 'Q12']);
for (i = 1; i < getLastRow; i++) {
var badgeStatus = mastersheet.getRange(i + 1, 5).getValue();
if (badgeStatus == "") {
var employeeNumber = mastersheet.getRange(i + 1, 1).getValue();
var employeeName = mastersheet.getRange(i + 1, 2).getValue();
copyCard.getRange("H3").setValue(employeeNumber);
copyCard.getRange("C3").setValue(employeeName);
SpreadsheetApp.flush();
getID.makeCopy(employeeNumber, destinationFolder);
mastersheet.getRange(1 + i, 5).setValue("completed");
SpreadsheetApp.flush();
var files = DriveApp.getFolderById(SpreadsheetApp.openById("Gsheet1-xxxx").getSheetByName("Config Sheet").getRange("B1").getValue()).getFiles();
while (files.hasNext()) {
var file = files.next();
Logger.log(file.getName());
var Found = false;
for (var j = 0; j < employeeNumber2.length; i++) {
if (employeeNumber2[j][0] == file.getName()) {
Found = true;
}
}
if (Found) {
continue;
}
try {
var fileId = file.getId();
var fileName = file.getName();
var revisions = Drive.Revisions.list(fileId);
var lastRevisionId = revisions.items[revisions.items.length - 1].id;
// get the resource and set the publish parameters
var resource = Drive.Revisions.get(fileId, lastRevisionId);
// Logger.log(resource);
resource.published = true;
resource.publishAuto = true;
resource.publishedOutsideDomain = true;
// publish to the web
Drive.Revisions.update(resource, fileId, lastRevisionId);
SpreadsheetApp.flush();
var openByID = SpreadsheetApp.openById(fileId);
SpreadsheetApp.flush();
var googleDriveSheet = openByID.getUrl().replace("edit", "pubhtml"); // or replace("edit", "pub");
SpreadsheetApp.flush();
mastersheet.getRange(1 + j, 9).setValue(googleDriveSheet);
SpreadsheetApp.flush();
} catch (err) {
Logger.log(err);
}
}
}
}
}
Change var getLastRow = mastersheet.getLastRow(); to var getLastRow = mastersheet.getLastRow()-1;
The reason why is because you've started to get your data from the
second row.
If you would start at the third, you should do var getLastRow = mastersheet.getLastRow()-2; ...
I have a functioning script that grabs all CSV attachments in Gmail, and puts them into a folder on Google Drive. It then removes the old file.
This is required because I have scheduled reports emailed to me every day. The old CSVs must be removed.
Now I need to convert the CSV file to Google Spreadsheet, without creating multiple files of the same name.
I used the Drive API to copy the file with the parameter {convert: true}. This will just create a duplicate spreadsheet every time, which I don't want. I have removed this code. Here is the functioning script that just moves the CSV file and deletes the old CSV file:
// GLOBALS
//Array of file extension which you would like to extract to Drive
var fileTypesToExtract = ['csv'];
//Name of the folder in google drive i which files will be put
var folderName = 'GmailToDrive';
//Name of the label which will be applied after processing the mail message
var labelName = 'GmailToDrive';
function GmailToDrive(){
//build query to search emails
var query = '';
//filename:jpg OR filename:tif OR filename:gif OR fileName:png OR filename:bmp OR filename:svg'; //'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);
}
var root = DriveApp.getRootFolder();
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 isDefinedType = checkIfDefinedType_(attachment);
if(!isDefinedType) continue;
var AttachmentTitle = attachment.getName();
var attachmentBlob = attachment.copyBlob();
var existingFile = DriveApp.getFilesByName(attachment.getName());
if (existingFile.hasNext()) {
var file = existingFile.next();
file.setTrashed(true);
}
var filetemp = DriveApp.createFile(attachmentBlob);
parentFolder.addFile(file);
root.removeFile(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 date = new Date();
date.setDate(date.getDate() - n);
return Utilities.formatDate(date, Session.getScriptTimeZone(), 'yyyy/MM/dd');
}
function getGmailLabel_(name){
var label = GmailApp.getUserLabelByName(name);
if(!label){
label = GmailApp.createLabel(name);
}
return label;
}
//this function will check for filextension type.
// and return boolean
function checkIfDefinedType_(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;
}
Instead of trying to save the CSV on the drive and convert it into a Google Spreadsheet, you can
directly import the CSV from the attachment into a spreadsheet created for this purpose
Sample
var ss=SpreadsheetApp.create(attachment.getName());
var sheet=ss.getActiveSheet();
var csvData = Utilities.parseCsv(attachment.getDataAsString(), ",");
sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
var file=DriveApp.getFileById(ss.getId())
parentFolder.addFile(file);
root.removeFile(file);
Full code:
function GmailToDrive(){
//build query to search emails
var query = '';
//filename:jpg OR filename:tif OR filename:gif OR fileName:png OR filename:bmp OR filename:svg'; //'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);
}
var root = DriveApp.getRootFolder();
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 isDefinedType = checkIfDefinedType_(attachment);
if(!isDefinedType) continue;
var AttachmentTitle = attachment.getName();
var files = DriveApp.getFilesByName(AttachmentTitle);
while (files.hasNext()) {
var file = files.next();
Logger.log(file.getName());
file.setTrashed(true);
}
var ss=SpreadsheetApp.create(attachment.getName());
var sheet=ss.getActiveSheet();
var csvData = Utilities.parseCsv(attachment.getDataAsString(), ",");
sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
var file=DriveApp.getFileById(ss.getId())
parentFolder.addFile(file);
root.removeFile(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 date = new Date();
date.setDate(date.getDate() - n);
return Utilities.formatDate(date, Session.getScriptTimeZone(), 'yyyy/MM/dd');
}
function getGmailLabel_(name){
var label = GmailApp.getUserLabelByName(name);
if(!label){
label = GmailApp.createLabel(name);
}
return label;
}
//this function will check for filextension type.
// and return boolean
function checkIfDefinedType_(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;
}
I have a script that iterates through a folder, opens all spreadsheets, and copies a certain array/range of these sheets to an archive sheet. My script functions just fine [on Folders containing files], but I can't figure out how to get my script to iterate through sub-folders as well.
I know that I'm going to have time-out issues eventually. But I'm going to look at setting up a token to have it continue where it left off once I can get it to iterate through the whole folder structure. (So not a problem for now.)
An example of my folder structure is as follows:
Master Folder
---Teacher Name (Folder)
-----Reading Assessment Data (Folder)
-------Spreadsheet
-------Spreadsheet
-------Spreadsheet
-----Math Assessment Data (Folder)
-------Spreadsheet
-------Spreadsheet
-------Spreadsheet
---Teacher Name (Folder)
-----This Continues...
Any help you guys can give me would be greatly appreciated!
Thanks,
Brandon
function runDataReport () {
var folder = DriveApp.getFolderById("ID");
Logger.log('folder: ' + folder);
var sheetFiles = folder.getFilesByType("application/vnd.google-apps.spreadsheet");
Logger.log("sheetFiles.hasNext(): " + sheetFiles.hasNext());
var data;
while (sheetFiles.hasNext()) {
var file = sheetFiles.next();
var theFileType = file.getMimeType();
Logger.log("theFileType: " + theFileType);
var ssID = file.getId();
Logger.log('ssID: ' + ssID);
var thisSS = SpreadsheetApp.openById(ssID),
ssName = thisSS.getName(),
ssUrl = thisSS.getUrl(),
classData = thisSS.getSheets()[0],
dataLastRow = classData.getLastRow(),
Avals = classData.getRange("A1:A").getValues(),
Alast = Avals.filter(String).length,
Jvals = classData.getRange("J2:J").getValues(),
Jlast = Jvals.filter(String).length,
classDataRange = classData.getRange(3, 1, Alast-2, 50),
dataArray = classDataRange.getValues();
var dataReportSS = SpreadsheetApp.openById('ID'), //Data Report Sheet ID
dataReportSheet = dataReportSS.getSheets()[0],
dataReportNewRow = dataReportSheet.getLastRow() + 1,
newDataRange = dataReportSheet.getRange(dataReportNewRow, 3, Alast-2, 50);
if (Jlast > 1){
newDataRange.setValues(dataArray);
for (var i=0, x = dataArray.length; i<x; i++){
dataReportSheet.getRange(dataReportNewRow + i, 1).setValue(ssName);
}
for (var i=0, x = dataArray.length; i<x; i++){
dataReportSheet.getRange(dataReportNewRow + i, 2).setValue(ssUrl);
}
}
}
}
Here is some code that I hope works for you. I didn't test it, so let me know if there are any problems.
function runDataReport () {
var allFoldersInThisDrive = DriveApp.getFolders();
var foldersToExclude = ["folder1","folder2","folder3"];
while (allFoldersInThisDrive.hasNext()) {
var folder = allFoldersInThisDrive.next();
//Logger.log(allFoldersInThisDrive.getName());
var thisFolderName = folder.getName();
//If index is -1, then thisFolderName was not found in the folders to exclude
if (foldersToExclude.indexOf(thisFolderName)===-1) {
//branch to another function in order to interate through all the files in this folder
processAllFiles(folder)
};
};
}
function processAllFiles(argFolder) {
var sheetFiles = argFolder.getFilesByType("application/vnd.google-apps.spreadsheet");
Logger.log("sheetFiles.hasNext(): " + sheetFiles.hasNext());
var data;
while (sheetFiles.hasNext()) {
var file = sheetFiles.next();
var theFileType = file.getMimeType();
Logger.log("theFileType: " + theFileType);
var ssID = file.getId();
Logger.log('ssID: ' + ssID);
var thisSS = SpreadsheetApp.openById(ssID),
ssName = thisSS.getName(),
ssUrl = thisSS.getUrl(),
classData = thisSS.getSheets()[0],
dataLastRow = classData.getLastRow(),
Avals = classData.getRange("A1:A").getValues(),
Alast = Avals.filter(String).length,
Jvals = classData.getRange("J2:J").getValues(),
Jlast = Jvals.filter(String).length,
classDataRange = classData.getRange(3, 1, Alast-2, 50),
dataArray = classDataRange.getValues();
var dataReportSS = SpreadsheetApp.openById('The ID here'), //Data Report Sheet ID
dataReportSheet = dataReportSS.getSheets()[0],
dataReportNewRow = dataReportSheet.getLastRow() + 1,
newDataRange = dataReportSheet.getRange(dataReportNewRow, 3, Alast-2, 50);
if (Jlast > 1){
newDataRange.setValues(dataArray);
for (var i=0, x = dataArray.length; i<x; i++){
dataReportSheet.getRange(dataReportNewRow + i, 1).setValue(ssName);
}
for (var i=0, x = dataArray.length; i<x; i++){
dataReportSheet.getRange(dataReportNewRow + i, 2).setValue(ssUrl);
}
}
}
};