I am trying to write a script to search my Google Drive for a file. The search should only look at the name of the file (not the contents), and look for a string within that name.
For example, there's a file called "2018-08-06_Miller_576132063_17.25.pdf" and I want to have my script search for "576132063" and get the fileID.
If it matters, I would be searching within subfolders of folder: "0B1-kfT4ZOAitb1lZSzM5YXR6czA"
function FileFinder() {
var ShowMeCC = '576132063';
var files = DriveApp.getFolderById('0B1-kfT4ZOAitb1lZSzM5YXR6czA').searchFiles('title contains "' + ShowMeCC + '" ');
while (files.hasNext()) {
var file = files.next();
var fnaMe = file.getName();
var fID = file.getId();
Logger.log(fID);
}
}
The search finds nothing.
This seems basic, yet I can't find anyone who asked this specific question.
Thanks in advance!
You want to retrieve files which have the filename including the string of ShowMeCC.
If my understanding is correct, how about this workaround?
The official document says as follows.
The contains operator only performs prefix matching for a title. For example, the title "HelloWorld" would match for title contains 'Hello' but not title contains 'World'.
By this, unfortunately, the file of 2018-08-06_Miller_576132063_17.25.pdf cannot be directly retrieved using title contains '576132063'. So as a workaround, it is considered the following workaround.
Search the file after all files were retrieved.
In this case, at first, it is required to retrieve all files. But this is the high cost. In order to reduce the cost, I would like to propose 2 step searching.
Retrieve files using the query of fullText contains '576132063'.
fullText contains '576132063' can search the filename like 2018-08-06_Miller_576132063_17.25.pdf.
Retrieve the file from files retrieved by fullText contains '576132063'.
By this flow, all files are not required to be retrieved. So the cost becomes lower than that of above method.
Modified script 1:
function FileFinder() {
var ShowMeCC = '576132063';
var files = DriveApp.searchFiles('fullText contains "' + ShowMeCC + '"'); // Modified
// OR var files = DriveApp.getFolderById('0B1-kfT4ZOAitb1lZSzM5YXR6czA').searchFiles('fullText contains "' + ShowMeCC + '"'); // Modified
while (files.hasNext()) {
var file = files.next();
var fnaMe = file.getName();
if (fnaMe.indexOf(ShowMeCC) > -1) { // Added
var fID = file.getId();
Logger.log(fnaMe);
Logger.log(fID);
}
}
}
Reference:
Search for Files
If this modification was not the result you want, I apologize.
Added:
As one more sample, if you want to retrieve the file from a specific folder like DriveApp.getFolderById('0B1-kfT4ZOAitb1lZSzM5YXR6czA'), you can also use the following script. When the number of files in the folder is not much, the cost of this method will not become high.
Modified script 2:
function FileFinderaaa() {
var ShowMeCC = '576132063';
var files = DriveApp.getFolderById('0B1-kfT4ZOAitb1lZSzM5YXR6czA').getFiles();
while (files.hasNext()) {
var file = files.next();
var fnaMe = file.getName();
if (fnaMe.indexOf(ShowMeCC) > -1) {
var fID = file.getId();
Logger.log(fnaMe);
Logger.log(fID);
}
}
}
Related
I am accessing a list of folders from a shared drive.
In here, I am converting a few excel files into spreadsheet. My issue is to replace the old converted files with the new file. This is because every time i run the script the new converted file(with same name) keeps on multiplying in the same folder together with the old one.
Here is the code:
function ConvertFiles() {
var sheet =
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var r= 2;
for(r= 2;r < sheet.getLastRow(); r++){
// Use getValue instead of getValues
var fileId = sheet.getRange(r,1).getValue();
var folderID = sheet.getRange(r,8).getValue();
var files = DriveApp.getFileById(fileId);
var name = files.getName().split('.')[0];
var blob = files.getBlob();
var newFile = {
// Remove '_converted' from name if existing to avoid duplication of the string before adding '_converted'
// This will allow to have newly converted file "replace" the old converted file properly
title: name.replace('_converted','') + '_converted',
parents: [{
id: folderID
}]
};
var destinationFolderId = DriveApp.getFolderById(folderID);
var existingFiles = destinationFolderId.getFilesByName(newFile.title);
// GOAL #1: To replace/update the old converted file into the latest one everytime the script runs (if it has the same filename)
// Find the file with same name of the file to be converted
while(existingFiles.hasNext()) {
// ID of the file with same converted name
var oldConvertedFileWithSameNameID = existingFiles.next().getId();
// Delete before writing
Drive.Files.remove(oldConvertedFileWithSameNameID);
//DriveApp.getFileById(oldConvertedFileWithSameNameID.getId()).setTrashed(true);
}
// Create new converted file then get ID
var newFileID = Drive.Files.insert(newFile, blob, { convert: true,supportsAllDrives: true }).id;
Logger.log(newFileID);
//var sheetFileID = newFileID.getId();
//var Url = "https://drive.google.com/open?id=" + sheetFileID;
var Url = "https://drive.google.com/open?id=" + newFileID;
// Add the ID of the converted file
sheet.getRange(r,9).setValue(newFileID);
sheet.getRange(r,10).setValue(Url);
}
}
My goal is
To replace the old converted file with the new one(if they have the same name) into the shared drive folder
To get to know how can i implement the setTrashed() inside the above code
I have tried using the Drive.Files.remove(oldConvertedFileWithSameNameID); but I am getting an error message GoogleJsonResponseException: API call to drive.files.delete failed with error: File not found:("fileid"). Then i saw an question on this [https://stackoverflow.com/questions/55150681/delete-files-via-drive-api-failed-with-error-insufficient-permissions-for-this]...so i guess that method is not suitable to implemented in shared folder.
So i how can i use setTrashed() method inside the above code?
I think you need to set the supportsAllDrives parameter:
Drive.Files.remove(oldConvertedFileWithSameNameID, {supportsAllDrives: true});
References:
Files:delete | Google Drive API | Google Developers - Parameters
In Google Drive, I'm searching for a specific file that contain words "Verification Visit" and "completed" where the file type need to be a spreadsheet(.xlsx) type file. The searching will go through a parent folder and then into sub folders. So the particular files will be stored in some of the sub folders (Google Drive -> Parent folder -> Sub folders).
Here is the code:
function getChildFolders(parentName, parent, sheet, voidFolder, excluded) {
var childFolders = parent.getFolders();
var folder = childFolders.next();
var failIter = folder.searchFiles('title contains "completed"');
while (failIter.hasNext()) {
var fail = failIter.next();
var failWithTitle = fail.getName();
var files = folder.getFilesByType(MimeType.MICROSOFT_EXCEL);
var output = [];
var path;
var Url;
var fileID;
while (files.hasNext()) {
var childFile = files.next();
var fileName = childFile.getName();
path = parentName + ' |--> ' + fileName;
fileID = childFile.getId();
Url = 'https://drive.google.com/open?id=' + fileID;
output.push([fileID, fileName, path, Url]);
}
if (output.length) {
var last_row = sheet.getLastRow();
sheet.getRange(last_row + 1, 1, output.length, 4).setValues(output);
}
getChildFolders(
parentName + ' |--> ' + fileName,
folder,
sheet,
voidFolder,
excluded
);
}
}
I have successfully implemented the two conditions (file that contains specific name and also the file type) in this function. The problem here is the searching process of the file in the sub folder only does on the first sub folder and it doesn't proceed searching into the next sub folder. It only list the files from the first sub folder but not from the other sub folders.
I am getting an error message telling "Exception: Cannot retrieve the next object: iterator has reached the end."
Issues:
You are not checking whether parent.getFolders() returns any folder, so when you reach the end of the hiearchy and there are no further subfolders on that level, childFolders.next(); fails with the error you are getting.
You are not iterating through the FolderIterator (for example, with while (folderIter.hasNext()) {), so you are only getting the first folder in the iterator.
You are iterating through the files that contain completed, but inside each file iteration you are iterating again with folder.getFilesByType to check the MIME type (check the available search query terms). That is to say, you are iterating through the files in that folder twice, which will most likely return duplicate results.
Suggested workflow:
For each folder, look for your desired files with Folder.searchFiles with the two conditions you want (title contains completed and mime type corresponds to MS Excel) and iterate through the results with FileIterator.hasNext() in a while loop.
For each folder, look for the corresponding subfolders via Folder.getFolders(), and loop through the results with FolderIterator.hasNext() and a while loop. For each of these subfolders, call your function recursively.
Use SpreadsheetApp.flush to make sure the sheet gets updated every time setValues is used, so that previous data is not overwritten.
Code sample:
function getChildFiles(folderName, folder, sheet) {
var fileIter = folder.searchFiles("title contains 'completed' and mimeType='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'");
var folderId = folder.getId();
var output = [];
while (fileIter.hasNext()) { // Iterate through files in folder
var file = fileIter.next();
var fileName = file.getName();
var path = folderName + ' |--> ' + fileName;
var fileID = file.getId();
var Url = 'https://drive.google.com/open?id=' + fileID;
output.push([fileID, fileName, path, Url, folderId]);
}
if (output.length) {
var last_row = sheet.getLastRow();
sheet.getRange(last_row + 1, 1, output.length, output[0].length).setValues(output);
SpreadsheetApp.flush();
}
var childFolders = folder.getFolders();
while (childFolders.hasNext()) { // Iterate through folders in folder
var childFolder = childFolders.next();
var childFolderName = childFolder.getName();
getChildFiles(
folderName + ' |--> ' + childFolderName,
childFolder,
sheet
);
}
}
I am currently using this code to automatically convert all uploaded .xls files in Google Drive to Google Sheets.
function importXLS(){
var files = DriveApp.searchFiles('title contains ".xls"');
while(files.hasNext()){
var xFile = files.next();
var name = xFile.getName();
if (name.indexOf('.xls')>-1){
var ID = xFile.getId();
var xBlob = xFile.getBlob();
var newFile = { title : name,
key : ID,
'parents':[{"id":"12FcKokB-ppW7rSBtAIG96uoBOJtTlNDT"}]
}
file = Drive.Files.insert(newFile, xBlob, {
convert: true
});
}
}
}
It works perfectly, but fails if there is already a file in the output folder with the same name. Even though I never technically get to see this error below (since it runs on a schedule and not fired manually like in the screenshot), I would prefer to simply skip the conversion process if the file already exists.
If possible, I would also like to avoid overwriting it each time, as I feel that would be a waste of processing time. How would I edit this code to say that if the file name already exists in that folder, skip the entire code completely?
Thanks!
Two things you can try:
Get the files names that are already in the destination folder and check if the file exists before you try copying.
Wrap the section of your code that does the copying in a try..catch statement.
Both of these should work independently, but using the try..catch statement will catch all errors, so it would be best to combine them. (You can review the error logs in the Developer Console.) Doing this you'll be able to skip files that have the same name as those already in your destination folder and any other error that might come up will not terminate your script from completing.
function importXLS(){
var files = DriveApp.searchFiles('title contains ".xls"');
var destinationFolderId = "12FcKokB-ppW7rSBtAIG96uoBOJtTlNDT";
var existingFileNames = getFilesInFolder(destinationFolderId);
while(files.hasNext()){
var xFile = files.next();
var name = xFile.getName();
try {
if (!existingFileNames[name] && (name.indexOf('.xls')>-1)) {
var ID = xFile.getId();
var xBlob = xFile.getBlob();
var newFile = { title : name,
key : ID,
'parents':[{"id": destinationFolderId}]
}
file = Drive.Files.insert(newFile, xBlob, {
convert: true
});
}
} catch (error) {
console.error("Error with file " + name + ": " + error);
}
}
}
/**
* Get an object of all file names in the specified folder.
* #param {string} folderId
* #returns {Object} files - {filename: true}
*/
function getFilesInFolder(folderId) {
var folder = DriveApp.getFolderById(folderId);
var filesIterator = folder.getFiles();
var files = {};
while (filesIterator.hasNext()) {
var file = filesIterator.next();
files[file.getName()] = true;
}
return files;
}
I'm trying to create documents using information posted through Google forms, then once the document is created I would like to move the document into a shared folder for people to view.
At the moment I have the script taking all of the information from the Google Forms linked spreadsheet.
Using that information I'm using the following code to create the document:
var targetFolder = DriveApp.getFolderById(TARGET_FOLDER_ID);
var newDoc = DocumentApp.create(requestID + " - " + requestSummary);
This is creating the document successfully in my Google Drive root folder, but I can't seem to move it where I want to move it to.
I've seen a lot of posts suggesting use stuff like targetFolder.addFile(newDoc) but that doesn't work, similarly I've seen examples like newDoc.addToFolder(targetFolder) but again this isn't working for me.
It seems that all the online questions people have already asked about this are using the previous API versions that are no longer applicable and these methods do not apply to the new DriveApp functionality.
What I would like, if possible, is to create the new document as above so that I can edit the contents using the script, then be able to move that file to a shared folder. (From what I understand there is no 'move' function at present, so making a copy and deleting the old one will suffice).
If we make a copy of the file and trash the original, it would change the file URL and also the file sharing settings won't be preserved.
In Drive, it is possible to add a file to multiple folders with the .addFolder() method of DriveApp service. You can add the file to the target folder and then remove the file from the immediate parent folder.
function moveFiles(sourceFileId, targetFolderId) {
var file = DriveApp.getFileById(sourceFileId);
var folder = DriveApp.getFolderById(targetFolderId);
file.moveTo(folder);
}
This is my first post! I know this has been answered a few times, but I actually came across this question while working on my project, and while reviewing the Apps Script documentation, I figured out a concise way to do it. A variation of some1's answer.
var file = DriveApp.getFileById(fileid);
DriveApp.getFolderById(folderid).addFile(file);
DriveApp.getRootFolder().removeFile(file);
Hope it helps!
There is no direct method in the File or Folder Classes to move files from one folder in Google Drive to another. As you mentioned you can copy the file to another folder with the method makeCopy() and then delete it with setTrashed(), the code should look like this:
var targetFolder = DriveApp.getFolderById(TARGET_FOLDER_ID);
var newDoc = DocumentApp.create(requestID + " - " + requestSummary); // Creates the Document in the user's Drive root folder
// Modify the new document here, example:
// var body = newDoc.getBody();
// body.appendParagraph("A paragraph.");
// newDoc.saveAndClose();
var driveFile = DriveApp.getFileById(newDoc.getId()); // Gets the drive File
driveFile.makeCopy(newDoc.getName(), targetFolder); // Create a copy of the newDoc in the shared folder
driveFile.setTrashed(true); // sets the file in the trash of the user's Drive
EDIT:
In a second thought and taking into account Ruben's comments. I agree that it is a better practice to implement Amit's answer.
It looks like there is now a moveTo() function with the Drive API (advanced services) that makes it easy to move files:
moveTo(destination)
Moves this item to the provided destination folder.
The current user must be the owner of the file or have at least edit
access to the item's current parent folder in order to move the item
to the destination folder.
Here is some code I used to move all files from the "screenshot input" folder to the "screenshot processed" folder:
var inputFolder = DriveApp.getFolderById(SCREENSHOT_INPUT_FOLDER_ID);
var processedFolder = DriveApp.getFolderById(SCREENSHOT_PROCESSED_FOLDER_ID);
var files = inputFolder.getFiles();
while (files.hasNext()) {
var file = files.next();
file.moveTo(processedFolder);
}
A bit safer approach compared to the previous ones:
If you remove link to the file first, then you will not be able to addFile.
If file is already located in the target folder, then the approach provided by Amit (https://stackoverflow.com/a/38810986/11912486) only removes file.
So, I suggest to use the following approach:
function move_file(file_id, target_folder_id) {
var source_file = DriveApp.getFileById(file_id);
var source_folder = source_file.getParents().next();
if (source_folder.getId() != target_folder_id) {
DriveApp.getFolderById(target_folder_id).addFile(source_file);
source_folder.removeFile(source_file);
}
}
can be improved by:
javascript camel style
multiple locations validation
Use File.moveTo(destination).
var newFileId = newDoc.getId();
var newFile = DriveApp.getFileById(newFileId);
newFile.moveTo(targetFolder);
Try this:
var file = DriveApp.getFileById(newDoc.getId());
targetFolder.addFile(file);
//DriveApp.getFolderById('root').removeFile(file); // remove from root
This question has been answered, but here is a slightly different configuration:
function moveFile(parameterObject) {
var currentFolderID,file,fileToMoveID,sourceFolder,targetFolder,targetFolderID;
fileToMoveID = parameterObject.fileToMoveID;
currentFolderID = parameterObject.currentFolderID;
targetFolderID = parameterObject.targetFolderID;
file = DriveApp.getFileById(fileToMoveID);//Get the file to move
if (!file) {
functionToHandleThisKindOfThing("there is no file");
return;
}
if (currentFolderID) {//The folder ID holding the current file was passed in
sourceFolder = DriveApp.getFolderById(currentFolderID);
} else {//No ID for the current folder
sourceFolder = file.getParents();
if (sourceFolder) {
if (sourceFolder.hasNext()) {
sourceFolder = sourceFolder.next();
}
}
}
targetFolder = DriveApp.getFolderById(targetFolderID);
targetFolder.addFile(file);
sourceFolder.removeFile(file);
}
function testCode() {
var o;
o = {
'fileToMoveID':"File ID of file to Move",
"targetFolderID":"ID of folder to Move to"
}
moveFile(o);
}
The script transfers all your personal files to a shared disk (Team drive). Saves the folder structure.
DRIVE_FOLDER_ID = '111aaa'; // Folder ID on the shared drive
function start() {
var files = DriveApp.searchFiles('"me" in owners');
while (files.hasNext()) {
var file = files.next();
newPath = fileMoveWithPath(file, DRIVE_FOLDER_ID);
console.info("New path: ", getFullPath(newPath));
}
}
function fileMoveWithPath(file, root) {
var folders = [],
parent = file.getParents();
// Проходим по иерархии папок текущего файла до корня
while (parent.hasNext()) {
parent = parent.next();
folders.push(parent);
parent = parent.getParents();
}
console.info("Old path: ", getFullPath(file));
if (folders.length > 0)
targetPath = makeNewPath(folders, DriveApp.getFolderById(root));
else
targetPath = DriveApp.getFolderById(root);
if (targetPath) {
targetFile = file.moveTo(targetPath);
return targetFile;
};
return;
}
function makeNewPath(folders, newroot) {
var f = folders.pop();
var query = "'" + newroot.getId() + "' in parents and title = '" + f.getName() + "' and mimeType='application/vnd.google-apps.folder' "
var targetFolder = DriveApp.searchFolders(query);
if (targetFolder.hasNext())
targetFolder = targetFolder.next()
else
targetFolder = newroot.createFolder(f.getName());
if (folders.length > 0)
return makeNewPath(folders, targetFolder)
else
return targetFolder;
}
function getFullPath(file) {
var folders = [],
parent = file.getParents();
while (parent.hasNext()) {
parent = parent.next();
folders.push(parent.getName());
parent = parent.getParents();
}
if (folders.length) {
return '> /' + folders.reverse().join("/") + '/' + file.getName();
}
return '> /' + file.getName();
}
In Google Drive I'm trying to search for a file in the current directory. The script is linked to a spreadsheet, so it finds the spreadsheet's parent directory, then uses its id to specify a search within the folder for a file named Title.
The code I have so far is:
function searchFolder(){
//get current folder id
var ss = SpreadsheetApp.getActive(); //current spreadsheet
var directParents = DriveApp.getFileById(ss.getId()).getParents();
while( directParents.hasNext() ) {
var folder = directParents.next();
var folderId = folder.getId();
Logger.log(folder.getName() + " has id " + folderId);
}
//get files in folder
var parent = DriveApp.getFolderById(folderId); // folder Id
var search = 'name contains "Title"';
var specificFolder = parent.searchFiles(search);
while (specificFolder.hasNext()) {
var file = specificFolder.next();
Logger.log(file.getName());
Logger.log(file.getId());
}
}
I get the error "Invalid argument: query" at the beginning of the while loop, which suggests that no files were found.
This error seems to only occur when I search by name. If I change the search variable to 'fullText contains "hello"' (the file Title has 'hello' in it) then there are no problems. What can be done to make the search by name work?
To replicate the error, make two spreadsheets in a folder on google drive. One spreadsheet has the script linked to it, the other is named "Title" and is being searched. Thanks.
As Srikanth pointed, it is title contains not name contains. The code could be made simpler, please try the following code. You don't need a spreadhseet for this, just use simple Google Apps Script project file. Right click on empty space of your Drive ---> More ---> Google Apps Script
function SearchFiles() {
//Please enter your search term in the place of Letter
var searchFor ='title contains "Letter"';
var names =[];
var fileIds=[];
var files = DriveApp.searchFiles(searchFor);
while (files.hasNext()) {
var file = files.next();
var fileId = file.getId();// To get FileId of the file
fileIds.push(fileId);
var name = file.getName();
names.push(name);
}
for (var i=0;i<names.length;i++){
Logger.log(names[i]);
Logger.log("https://drive.google.com/uc?export=download&id=" + fileIds[i]);
}
}
Also check these links:
1) Search all documents in a folder
2)Search Drive Files