Getting Google Sheet URL from Name - google-apps-script

I have a google sheet file that needs to find the URL of another google sheet where only its name is known (I need its URL so I can retrieve the data externally through other apps).
To simplify this, I save both g-sheets files under the same folder in Google Drive. I understand I can do this within the same sheet as below, how can I do this when the "ss" refers to another google sheet file and I only know its name.
var ss = SpreadsheetApp.getActiveSpreadsheet();
Logger.log(ss.getUrl());
Ideally I want to do it through a cell formula but will be ok if I need to add a function to "script editor".

I got it working till here where it runs ok from the Script editor:
function listFiles() {
var baseFolderObject = DriveApp.getFolderById('0B38VWNq67cFHZVdWcE5KREZXS1U');
var results = [];
var types = [MimeType.GOOGLE_SHEETS]; //, MimeType.GOOGLE_DOCS];
for (var t in types) {
var files = baseFolderObject.getFilesByType(types[t]);
var file, data, sheet = SpreadsheetApp.getActiveSheet();
sheet.appendRow(["Name", "Date", "Size", "URL", "Download", "Description", "Type"]);
while (files.hasNext()) {
var file = files.next();
results.push(file);
data = [
file.getName(),
file.getDateCreated(),
file.getSize(),
file.getUrl(),
file.getId()
];
sheet.appendRow(data);
}
}
}

If you have the id of the folder both spreadsheets are in, why not run a query on the folder and filter out the file you are looking for by name.. Once you have that file, then grab it's id.. With the ID you can then parse it into a google spreadsheet URL. Hope this helps.

Related

Copying XLSX file to GSheet in Google Drive

I'm trying to copy over an XLSX sheet to an existing Gsheet, both are in the same GDrive folder. This script works when I run it as Drive.Files.insert() but that causes multiple version of the file to be created each time the script is run - so I switched it over to Drive.Files.update() like below....
function importXLS(){
var myFolder= "XXXXXXXXXX"; // Set the folder ID of "FolderB" if you want to copy over to a different folder
var files = DriveApp.getFolderById(myFolder).searchFiles('title = "XXXXX.xlsx"');
while(files.hasNext()){
var xFile = files.next();
var name = xFile.getName();
if (name.indexOf('.xlsx')>-1){
var ID = xFile.getId();
var xBlob = xFile.getBlob();
var newFile = {
title : name + '_converted',
parents: [{'id': myFolder}],
supportsAllDrives: true
};
file = Drive.Files.update(newFile, xBlob, { //Originally using Drive.Files.insert() but was creating multiple versions. I want to overwrite the existing version.
convert: true, supportsAllDrives: true
});
}
}
}
But I'm getting the following error when this runs...
Exception: The mediaData parameter only supports Blob types for upload.
Any idea on what I'm doing wrong? This is my first time using Google Apps Script and javascript so I'm kinda flying blind here.
I believe your goal is as follows.
You have a folder in Google Drive. There are XLSX files and Google Spreadsheets in the folder.
You want to overwrite the Google Spreadsheet with the XLSX file by searching the filename.
Filename of the XLSX file is like XXXXX.xlsx.
Filename of the Google Spreadsheet file is like XXXXX.xlsx_converted.
Modification points:
In the case of Drive.Files.update, it is required to include the file ID of the target file.
In your script, the file ID of the target Spreadsheet is not retrieved.
The 2nd argument of Drive.Files.update is required to be the file ID. But, your script uses blob. I thought that this might be the reason for your current issue.
When these points are reflected in your script, how about the following modification?
Modified script:
function importXLS() {
var myFolder = "XXXXXXXXXX"; // Please set the folder ID.
var filename = "XXXXX.xlsx"; // Please set the filename of XLSX file.
var folder = DriveApp.getFolderById(myFolder);
var files = folder.searchFiles(`title="${filename}" and mimeType="${MimeType.MICROSOFT_EXCEL}" and trashed=false`);
while (files.hasNext()) {
var xFile = files.next();
var name = xFile.getName();
if (name.indexOf('.xlsx') > -1) {
var xBlob = xFile.getBlob();
var spreadsheetFileName = name + '_converted';
var spreadsheet = folder.searchFiles(`title="${spreadsheetFileName}" and mimeType="${MimeType.GOOGLE_SHEETS}" and trashed=false`);
if (spreadsheet.hasNext()) {
Drive.Files.update(null, spreadsheet.next().getId(), xBlob, { convert: true, supportsAllDrives: true });
} else {
var newFile = { title: spreadsheetFileName, parents: [{ 'id': myFolder }] };
file = Drive.Files.insert(newFile, xBlob, { convert: true, supportsAllDrives: true });
}
}
}
}
When this script is run, the XLSX file of XXXXX.xlsx is retrieved from the specific folder. And, Google Spreadsheet of the filename of XXXXX.xlsx_converted is searched from the same folder. When the Spreadsheet is found, the Spreadsheet is overwritten by the XLSX file. When the Spreadsheet is not found, a new Spreadsheet is created by converting the XLSX file.
Reference:
Files: update

List Google drive folder contents to google sheets with only new files

Looking to learn how to improve my use of loops. Currently I need to list the names and URLS from a google drive Folder to a sheet and this is the code that I have:
Existing Code
function wthFolderContents() {
var folder_id = 'myFolderID';
var folders = DriveApp.getFolderById(folder_id)
var contents = folders.getFiles();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("SheetName");
sheet.clearContents()
sheet.appendRow( ['name', 'link'] );
var file;
var name;
var link;
var row;
while(contents.hasNext()) {
file = contents.next();
name = file.getName();
link = file.getUrl();
sheet.appendRow ( [name, link] );
with this code everytime the script is run the contents are cleared and then relisted. I am looking at a way of doing this dynamically / only update the new files so the script runs more effeciently.
Ive tried the following
New Code
function wthFolderContents2() {
var folder_id = '1vBzucZsb0SMOoHSWGtkUF-5QLQr5Fh1C';
var folders = DriveApp.getFolderById(folder_id)
var contents = folders.getFiles();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("WHTCert");
var lastRow = sheet.getLastRow()
var existing = sheet.getRange(1,1,lastRow,1).getValues()
for(i=1;i<lastRow;i++) {
var existingFilename = existing [i][0]
Logger.log(existingFilename)
while(contents.hasNext()) {
var file;
var name;
var link;
file = contents.next();
name = file.getName();
link = file.getUrl();
if (!name == existingFilename) {
sheet.appendRow ( [name, link] );
}
}
}
I cant get this to work, not sure what exactly where I have gone wrong. Hope someone can point me int he right direction!
Cheers
I believe your goal is as follows.
You want to reduce the process cost of your script.
Modification points:
In your script, appendRow is used. In this case, the process cost will become high. Ref
The search for files is run in a loop. In this case, the process cost will become high.
In your situation, it seems that you want to retrieve the file list just under the specific folder. In this case, I thought that when Drive API is used, the process cost can be reduced. In this answer, I would like to propose using Drive API in your script. When this is reflected in your script, it becomes as follows.
When Drive API is used, all values can be retrieved. So, I thought that your 1st process might be able to be used.
Modified script:
Before you use this script, please enable Drive API at Advanced Google services.
function wthFolderContents2() {
var folder_id = '1vBzucZsb0SMOoHSWGtkUF-5QLQr5Fh1C';
// Retrieve file list.
var q = `'${folder_id}' in parents and trashed = false and mimeType != '${MimeType.FOLDER}'`;
var fileList = [['name', 'link']];
var pageToken = "";
do {
var obj = Drive.Files.list({ q, maxResults: 1000, pageToken, fields: "nextPageToken,items(id,title)", corpora: "allDrives", supportsAllDrives: true, includeItemsFromAllDrives: true });
if (obj.items.length > 0) {
fileList = [...fileList, ...obj.items.map(({ id, title }) => [title, `https://docs.google.com/presentation/d/${id}/edit?usp=drivesdk`])];
}
pageToken = obj.nextPageToken;
} while (pageToken);
// Put the values to Spreadsheet.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("WHTCert");
sheet.clearContents();
sheet.getRange(1, 1, fileList.length, fileList[0].length).setValues(fileList);
}
When this script is run, the file list (filename and URL) is retrieved from the specific folder. And, the retrieved values to the "WHTCert" sheet.
Reference:
Files: list
Please convert this 2 script for scan folder only one subfolder and file, show folder name and link.
function wthFolderContents()
function wthFolderContents2()

Using Class CellImageBuilder to import Image into Google Sheets cell

On the 19th January 2022, the CellImageBuilder class was added to the Google Sheets Spreadsheet service.
This class now allows you to import an image into a cell in Google Sheets, previously you could only add an image above the cell.
Ive been trying to use this new class to take a URL link from a Google sheet, and then create an image in the cell next to the URL. This works perfectly fine if I can hard code the URL into the script (example below)
**function insertImageIntoCell()**
{
var sheet = SpreadsheetApp.getActiveSheet();
var url='Google_Docs_Image_URL'
let image = SpreadsheetApp.newCellImage().setSourceUrl(url).setAltTextDescription('TestImage').toBuilder().build();
SpreadsheetApp.getActive().getActiveSheet().getRange('C2').setValue(image);
}
The problem I am having is that once I create an array to iterate through the column the below script creates a valid array and posts it into the correct column and rows, but when it posts it back into the spreadsheet it only returns the URL and does not convert it into an image in a cell
**function insertImageIntoCell()**
{
var sheet = SpreadsheetApp.getActiveSheet();
var myStringArray = sheet.getRange('B2:B10');
var myStringArray = sheet.getRange('B2:B10').getValues();
//Logger.log(myStringArray)
let image = SpreadsheetApp.newCellImage().setSourceUrl(myStringArray).setAltTextDescription('test').toBuilder().build();
SpreadsheetApp.getActive().getActiveSheet().getRange('C2:C10').setValues(myStringArray);
}
Im using the followign code to create the initial table of data, this pull the file name and DownloadURL from a Google Drive location and then saves this into a sheet
/* modified from #hubgit and http://stackoverflow.com/questions/30328636/google-apps-script-count-files-in-folder
for this stackexchange question http://webapps.stackexchange.com/questions/86081/insert-image-from-google-drive-into-google-sheets by #twoodwar
*/
function listFilesInFolder(folderName) {
var sheet = SpreadsheetApp.getActiveSheet();
sheet.appendRow(["Name","URL","Image"]);
//change the folder ID below to reflect your folder's ID (look in the URL when you're in your folder)
var folder = DriveApp.getFolderById("Google_Drive_Folder");
var contents = folder.getFiles();
let image=[];
var cnt = 0;
var file;
while (contents.hasNext()) {
var file = contents.next();
cnt++;
data = [
file.getName(),
file.getDownloadUrl(),
];
sheet.appendRow(data);
};
};
I am looking for the script to refresh the file information from Google Drive into sheets, then to save the image into a cell, it now appears that this functionality exists, but Im not able to get it to take an array of URL's
Suggestion
Perhaps you can try this sample implementation below.
Sample Tweaked Script
function listFilesInFolder(folderName){
var sheet = SpreadsheetApp.getActiveSheet();
sheet.appendRow(["Name","URL","Image"]);
//change the folder ID below to reflect your folder's ID (look in the URL when you're in your folder)
var folder = DriveApp.getFolderById("DRIVE_FOLDER_ID");
var contents = folder.getFiles();
let image=[];
var cnt = 0;
var file;
while (contents.hasNext()) {
var file = contents.next();
cnt++;
data = [
file.getName(),
file.getDownloadUrl(),
];
sheet.appendRow(data);
};
insertImageIntoCell(); //Insert the images on column C
};
function insertImageIntoCell(){
var sheet = SpreadsheetApp.getActiveSheet();
var row = 1;
sheet.getDataRange().getValues().forEach(url =>{
if(url[1] == "URL")return row += 1;
let image = SpreadsheetApp.newCellImage().setSourceUrl(url[1]).setAltTextDescription('TestImage').toBuilder().build();
SpreadsheetApp.getActive().getActiveSheet().getRange('C'+row).setValue(image);
row += 1;
});
}
Sample Drive Folder with sample images
Sample Result:
After running the function listFilesInFolder:
Update:
This issue is filed. Add a star to this issue for Google developers to prioritize fixing this.
Issue:
setValues() is NOT working with CellImage, while setValue() does.
If/when it starts working, You need to convert each value to cellImage using map :
function insertImagesIntoCell() {
const sheet = SpreadsheetApp.getActiveSheet(),
range = sheet.getRange('B2:B10');
range.setValues(
range.getValues().map(url => [
SpreadsheetApp.newCellImage()
.setSourceUrl(url[0])
.build(),
])
);
}
For anyone struggling with importing images from Google Drive you should know that you have to set the "Sharing" setting on every individual file for CellImageBuilder to work properly.
Like this:
const imageFileUrl = imageFolder.getFilesByName(filename).next()
.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW)
.getDownloadUrl();
const cellImage = SpreadsheetApp.newCellImage().setSourceUrl(imageFileUrl).build();
Additionally, there appears to be a rate limit on the drive download URLs, causing the '.build()' function to fail randomly on a valid URL. Retries might be necessary.
Also, the .toBuilder() call on CellImageBuilder is completely redundant.

Is there a way to copy a specific sheet from one workbook to a specific (and different) folder as its own stand alone sheet in google?

I am not a developer or coder, just trying to learn and automate tasks*. This is what I have so far:
function saveAsSpreadsheet() {
var source = SpreadsheetApp.getActiveSpreadsheet();
var sheet = source.getSheets()[6];
var destFolder = DriveApp.getFolderById("xxxxxxxxxxxxxxxxxx");
DriveApp.getFileById(sheet.getSheetId()).makeCopy("desired file name", destFolder);
} //END function saveAsSpreadsheet
I get the error "Exception: Unexpected error while getting the method or property getFileById on object DriveApp."
Any tweaks that might make this work?
Issues:
You are trying to use the sheet id instead of spreadsheet id in DriveApp.getFileById(file id).
Using makeCopy(name, destination) will copy the content of the whole spreadsheet.
Try this:
function saveAsSpreadsheet() {
var folderId = "id";
var fileName = "new File";
var file = Drive.Files.insert({title: fileName, mimeType: MimeType.GOOGLE_SHEETS, parents: [{id: folderId}]});
var newFile = SpreadsheetApp.openById(file.id);
var source = SpreadsheetApp.getActiveSpreadsheet();
var sheet = source.getSheets()[0];
var sheetName = sheet.getSheetName();
sheet.copyTo(newFile).setName(sheetName);
}
Note: Make sure to add Drive API to the project Services. See how to add Services in Apps Script.
Example:
Source file:
Destination:
Reference:
Drive.Files.insert()

Extract text from several Google docs into Google Spreadsheet

I am trying to extract the text from each Google document in a folder in Drive and paste the text into the first column of a Google spreadsheet so that the contents of file 1 are in A1, the contents of file 2 in A2 etc. Ultimately I am trying to recreate a database of the information stored in all these files, so if the text can be split by field so much the better, but I think this should be trivial in Excel using Text to Columns.
I have used a few snippets online to have a stab at it but I'm now stumped.
Here is my script as it stands:
//Function to extract the body from each document in a folder and copy it to a spreadsheet
function extract() {
//Define the folder we're working with ("Communication Passports") and get the file list
var folder = DocsList.getFolder("Communication Passports");
var contents = folder.getFiles();
//Define the destination spreadsheet file (CP) and set up the sheet to receive the data
var ss = SpreadsheetApp.openById("0AicdFGdf-Cx5dHFTX1R3Wm1RTEFTZ2d5ZmxuSjJSOHc");
SpreadsheetApp.setActiveSpreadsheet(ss);
Logger.log('File name: ' + ss.getName());
var sheet = SpreadsheetApp.getActiveSheet();
sheet.clear();
sheet.appendRow(["Name", "Date", "Contents", "URL", "Download", "Description"]);
//Set up other variables
var file;
var data;
//Loop through and collect the data (I don't actually need this - just borrowed the code from a snippet online - but it is SO CLOSE!)
//Sadly, getBody doesn't work on files, only on documents
for (var i = 0; i < contents.length; i++) {
file = contents[i];
data = [
file.getName(),
file.getDateCreated(),
file.getViewers(),
file.getUrl(),
"https://docs.google.com/uc?export=download&confirm=no_antivirus&id=" + file.getId(),
file.getDescription()
];
sheet.appendRow(data);
//Extract the text from the file (this doesn't work at present, but is what I actually need)
var doc = DocumentApp.openById(file.getId());
var body = doc.getBody();
//Find a way to paste the extracted body text to the spreadsheet
}
};
Any help would be very gratefully received - I'm not a programmer, I'm a teacher and the information is about children's learning needs at our school (someone deleted the database over summer and our backups only go back a month!).
Thanks,
Simon
Try to add:
var doc = DocumentApp.openById(file.getId());
body = doc.getBody().getText();
to return the actual contents of the document.
I wrote another function to parse the content into more usable chunks and then pass back to an entry in the data table and it worked fine.