Tuesday, 29 June 2021

Bulk create Sheets from a Google Sheet

The following Google Apps Script is designed to bulk create Sheets from rows of data within a Google Sheet and to include some of that data within the new file in specific cells. It also creates a link to the new Google Sheet back in the original file on the relevant row.

For those wanting to bulk create Google Docs from a Google Sheet please see this blog post.

Bulk create Google Sheets from a Sheet of data by looping through each row.
Screenshot of Google Sheets data

It takes data from the first four columns and will copy that into the new Google Sheet template file that is created for that row.

There is a Config sheet where you will need to specify some further information:

  1. The ID of the Google Drive folder where you wish to store the newly created Google Sheets.
  2. The ID of the template Google Sheet that is to be copied for each row.
  3. The name of the Sheet/Tab in the template file where data is to be copied to. This option tries to make the tool universal as you may have other data in the Google Sheet that needs to be left untouched.
  4. The four cell references for each piece of data that it to be copied in to the newly created Google Sheet. Again to be universal this allows you to specify exactly which cells you want the information to be put into.

Download

Bulk create Sheets from a Google Sheet download here (please use 'File' > 'Make a copy' for your own version).

/*
This overall script is designed to bulk create Google Sheets from data within a Google Sheet.
*/
function getSpreadsheetData() {
// Log starting of the script
logEvent('Script has started');
// get current spreadsheet
var spreadsheet = SpreadsheetApp;
var ss = spreadsheet.getActiveSpreadsheet();
// display Toast notification to inform starting of the script
ss.toast('Script has now started', 'Start');
// get Config sheet
var configSheet = ss.getSheetByName('Config');
// get Drive Folder ID for storing created Docs
var destinationFolderId = configSheet.getRange(1, 2).getValue();
Logger.log('destinationFolderId is: ' + destinationFolderId);
// get Template File ID
var templateFileId = configSheet.getRange(2, 2).getValue();
Logger.log('templateFileId is: ' + templateFileId);
// get Cell References for mapping data
var destSheet = configSheet.getRange(3, 2).getValue();
var emailRef = configSheet.getRange(4, 2).getValue();
var firstRef = configSheet.getRange(5, 2).getValue();
var lastRef = configSheet.getRange(6, 2).getValue();
var shoeRef = configSheet.getRange(7, 2).getValue();
// get Data sheet
var dataSheet = ss.getSheetByName('Data');
// get all data as a 2-D array
var data = dataSheet.getDataRange().getValues();
// create a name:value pair array to send the data to the next Function
var spreadsheetData = {
spreadsheet: spreadsheet, dataSheet: dataSheet, destinationFolderId: destinationFolderId,
templateFileId: templateFileId, destSheet: destSheet, emailRef: emailRef, firstRef: firstRef, lastRef: lastRef, shoeRef: shoeRef, data: data
};
// run Function to create Google Sheets
createSheets(spreadsheetData);
}
function createSheets(spreadsheetData) {
// Log starting createDocs Function
logEvent('Starting createSheets Function');
// separate out data from name:value pair array
var spreadsheet = spreadsheetData['spreadsheet'];
var ss = spreadsheet.getActiveSpreadsheet();
var dataSheet = spreadsheetData['dataSheet'];
var destinationFolderId = spreadsheetData['destinationFolderId'];
var templateFileId = spreadsheetData['templateFileId'];
var destSheet = spreadsheetData['destSheet'];
var emailRef = spreadsheetData['emailRef'];
var firstRef = spreadsheetData['firstRef'];
var lastRef = spreadsheetData['lastRef'];
var shoeRef = spreadsheetData['shoeRef'];
var data = spreadsheetData['data'];
try {
// try getting the Folder and then set variable as true if successful
var destinationFolder = DriveApp.getFolderById(destinationFolderId);
var gotDestinationFolder = true;
}
catch (e) {
// if failed set variable as false and Log
var gotDestinationFolder = false;
logEvent('Failed to get destinationFolder with error: ' + e);
}
// only proceed if got destination Drive Folder
if (gotDestinationFolder) {
try {
// try getting the Template File and then set variable as true if successful
var templateFile = DriveApp.getFileById(templateFileId);
var gotTemplateFile = true;
}
catch (e) {
var gotTemplateFile = false;
logEvent('Failed to get templateFile with error: ' + e);
}
}
else {
// do nothing
}
// only proceed if got Template File also
if (gotTemplateFile) {
// loop through each row of data and create new Sheet ******************************
var dataLength = data.length;
for (var i = 1; i < dataLength; i++) {
// extract values from array of data
var emailAddress = data[i][0];
var firstName = data[i][1];
var lastName = data[i][2];
var shoeSize = data[i][3];
// create name for new File
var newFileName = 'Bulk create Sheets - ' + lastName + ', ' + firstName;
// make copy of Template File and place in destination Drive Folder
var newFile = templateFile.makeCopy(newFileName, destinationFolder);
// get ID and Url of new File
var newFileID = newFile.getId();
var newFileUrl = newFile.getUrl();
try {
// try opening the new File, get the named Sheet and then set variable as true if successful
var newFileBody = SpreadsheetApp.openById(newFileID).getSheetByName(destSheet);
var openNewFile = true;
}
catch (e) {
// if failed set variable as false and Log
var openNewFile = false;
logEvent('Failed to open newFileBody with error: ' + e);
}
// only proceed if got Body of new File
if (openNewFile) {
// replace tags with data from sheet
newFileBody.getRange(emailRef).setValue(emailAddress);
newFileBody.getRange(firstRef).setValue(firstName);
newFileBody.getRange(lastRef).setValue(lastName);
newFileBody.getRange(shoeRef).setValue(shoeSize);
// paste a hyperlink to new File in spreadsheet
var newFileLink = '=HYPERLINK("' + newFileUrl + '","' + newFileName + '")';
dataSheet.getRange(i + 1, 5).setFormula(newFileLink);
// refresh spreadsheet so links appear as soon as added
spreadsheet.flush();
// display Toast notification to confirm row complete
ss.toast('Row ' + (i + 1) + ': ' + newFileName, 'Completed Sheet');
}
else {
// do nothing
}
}
// loop through each row of data and create new Sheet ******************************
}
else {
// do nothing
}
// display Toast notification to inform end of the script
ss.toast('Script has now ended', 'End');
// Log end of the script
logEvent('Script has ended');
}
function logEvent(action) {
// get the user running the script
var theUser = Session.getActiveUser().getEmail();
// get the relevant spreadsheet to output log details
var ss = SpreadsheetApp.getActiveSpreadsheet();
var logSheet = ss.getSheetByName('Log');
// create and format a timestamp
var dateTime = new Date();
var timeZone = ss.getSpreadsheetTimeZone();
var niceDateTime = Utilities.formatDate(dateTime, timeZone, "dd/MM/yy @ HH:mm:ss");
// create array of data for pasting into log sheet
var logData = [niceDateTime, theUser, action];
// append details into next row of log sheet
logSheet.appendRow(logData);
}
/*
Create menu item to run script from spreadsheet.
*/
function onOpen() {
SpreadsheetApp.getUi()
.createMenu('Create Sheets')
.addItem('Create Sheets', 'getSpreadsheetData')
.addToUi();
}

9 comments:

  1. How can i use that script only for las entry row! with trigger on submit form? thanks for your great job!!

    ReplyDelete
    Replies
    1. Hi

      Are you referring more to wanting something like this: https://www.pbainbridge.co.uk/2020/05/create-google-doc-from-form-submission.html

      Kind regards
      Phil

      Delete
    2. exactly!im placing my orders via google form and i need to automatically creates the invoice from the last entry/row only.not the enrtries before! im using that function since today but its bulkPDf and i prefer the (EXCEL/sheet) outpout

      Delete
    3. This comment has been removed by the author.

      Delete
    4. Hi

      I'm not sure exactly which bit you're stuck with? In my code/example I use a Trigger that runs upon Form submission - which means it will only run for the last item submitted. Can you take my code and adapt it?

      Kind regards
      Phil

      Delete
    5. to explain better ..i will use the formo to docs code but i want to generate "sheet" files not "doc" thats what i need to change only. the output format.
      thank you Mr Phil

      Delete
    6. Rightio, so when the Form to Doc code makes a copy of a template file (line 108 on the GitHub code) you want to be making a copy of a Google Sheet here rather than a Google Doc file.
      Once you've done that bit, you can use the code on this blog post to paste over the values.

      Kind regards
      Phil

      Delete
  2. Hey there, Just wondering if I can put those duplicates into corresponding folders (I have got heaps of folderID)? So far, the destfolderID is limited to only one

    ReplyDelete
    Replies
    1. Hi

      Yes technically you could. You would need a column with each Folder ID, then as you iterate through each row, use the DriveApp to get that folder and work within it.

      The closest example that comes to mind is this post I have for bulk creating Drive folders and putting files into them: https://www.pbainbridge.co.uk/2021/11/bulk-create-google-drive-folders-and.html

      Kind regards
      Phil

      Delete