Searching Google Drive within a specific folder - google-drive-api

I am trying to utilize Google Drive as repository for many different types of documents. I have those documents arranged in several different folders.
When I perform a search it seems to search my entire Google Drive account for matching results regardless of the fact that I am currently within a specific folder.
This poses a problem for me as I want to be able to refine my searches to within a given grouping of documents.
If I am searching for documents related to my work, for instance, I don't want documents showing up in my search that are personal, or in my personal directories.
Is there a way to refine my search to only show documents within a specified folder and it's subfolders? I know I can refine the search based on file type and ownership, but that doesn't work for me.
Thanks in advance.

Using the Google Drive SDK, you can perform a search query for <folder_id> in parents.

The code I have included allows me to search the body of files within a specific folder. I am using it to search scanned documents and will have it move the file to another folder based on search criteria I specify.
The great thing about this is that it will search the body of the document and return all documents that meet your search criteria. As you can see I can also specify a date range and you can use other operators to define your search. https://developers.google.com/drive/web/search-parameters.
This was a great find for me and I hope it can help some others.
function searchFolder(){
var parent = DriveApp.getFolderById(‘*******************’); // folder Id
var search = 'modifiedDate >"2014-08-01" and modifiedDate < "2014-12-31" and fullText contains "PUT SEARCH TEXT HERE"';
var specificFolder = parent.searchFiles(search);
while (specificFolder.hasNext()) {
var file = specificFolder.next();
Logger.log(file.getName());
Logger.log(file.getId());
}
}

As far as I know you'd have to do this for each subfolder, but the API (and my app) will search by folder.
I wrote an app that uses the API to search by folder. It is a bit slow so be patient when it is loading.
https://script.google.com/macros/s/AKfycby6G32K-vKCiLmoKvMtG64cYPHEREEx1PY5IoYrEYaR6WAfbXs/exec
// -----------------
var sr = DocsList.getFolder("temp_scripts").find("var");
var i = 0;
for(i=0;i<sr.length;i++)
{
var r = sr[i];
Logger.log('name='+r.getName());
Logger.log('parent=' +r.getParents()[0].getName() );
Logger.log('---');
}
// -----------------

I found a sort of workaround using the description field.
In my particular case, all the files created in the folder i want to search are created programmatically by my own script, but is quite simple to write a script to (re)define the description field into all the files in a specific folder using .setDescription(DESCRIPTION). Once this is done...
The good news is that the standard search in google drive give results based on the description field, including the value set on it into the search field (plus any data you want to find into those files) you will get the results you need.
Of course you need to scarify the description field (or, at least, overcrowd it;-)
As, I think all of you, I'm still waiting for the folder keyword in the standard serch field.

I implemented the function in this Chrome Extension.
https://chrome.google.com/webstore/detail/advanced-drive-search/chomjcpadndbjgkanbaakmjehdoighab
You can check the code here
https://github.com/kissrobber/advanced_google_drive_search_chrome_extension
What that do is
get all the folders
build a query with the folder_id and the descendant folder_ids. Like this (<folder_id> in parents or <folder_id> in parents or ....)
If you have concern with the performance, try the Chrome extension.

There is another workaround that do NOT require any third party app or extension.
Remove your folder (In which you wanna search something)
Search with is:trashed filter. For example: is:trashed query_string
Restore your folder back

Related

Cant search files with underscore in name with Google Apps Script

I am using Google Apps Script to find files by name in my Drive account. I have problems with finding files whose names contain underscores.
For example, I have a file whose name is FB_51.pdf
This code does not retrieve the file
folder.searchFiles('title contains "51"');
This code does not retrieve the file
folder.searchFiles('title contains "_51"');
But this code retrieves the file
folder.searchFiles('title contains "FB_51"');
I'd like to retrieve the file only with the two digits "51".
Unfortunately, I believe what you are perceiving as a glitch, is actually considered "by design" from Google's perspective. Neither the Apps Script doc on searching, nor the page that doc links to mentions this, but I found the answer at the API docs page for search syntax, under a footnote:
The contains operator only performs prefix matching for a name. For example, the name "HelloWorld" would match for name contains 'Hello' but not name contains 'World'.
That seemed pretty conclusive to me, but just to be sure, I tested with your example:
In this case, Google treats the underscore as a normal character, not a delimiter or word boundary, so "FB_51" is treated as one single word, not "FB" and "51", and thus it can only match on an exact word match, or a prefix match (per the warning I put above).
Alternative
Other than forcing your files into a format that will fit the search syntax (e.g. swapping to 51_FB.pdf), or always prefixing your search term with FB_, if files always match that syntax, your options are pretty limited. Your best bet is likely to limit the start of your search to as narrow of a location as possible, for example a specific Drive folder, then get all files, iterate over them, and use Regex to match the filename. Example script:
function findNumberedPdf(folderId, number) {
var folder = DriveApp.getFolderById(folderId);
var files = folder.searchFiles("mimeType contains 'pdf'");
while (files.hasNext()) {
var file = files.next();
var regPattern = new RegExp(number);
if (regPattern.test(file.getName())) {
return file;
}
}
return false;
}
/**
* Test:
* Logger.log(findNumberedPdf('0CdI2-...', 51).getName());
* >> "FB_51.pdf"
*/
Of course, if your files really do always start with FB_, you could also just create a wrapper function to always prepend that string to your searches.
Note - why this is by design:
The reason why this is "by design" and Google seems to care about word boundaries and tokenization is because of how string matching works. Usually, when we search for something, we expect a full word (or similar word) match for each token in our search query. If searches didn't work this way, a search for "51" could pull up files like "fileA-v5251989.jpg" or a search for "cat" would match "multiplication" and "modification".
Google's "by design" has the consequence that if you or anybody place an underscore within a filename you render that file 'hard to search for' for you and any other users (say in GSuite).
Businesses that rely on Google Drive's feature for storage of compliance related documentation and expect Auditors to search for files (perhaps sometimes using filenames) are thus rendered into a 'compliance-unlikely' situation. An employee can accidentally or intentionally break business processes by adding an underscore. app systems that integrate with GDrive APIs and rely on a single, exact match for searches on filenames can be broken/dos attacked by Users simply by adding an underscore to a filename. A whole bunch of problem scenarios caused by Google's persistent unwillingness to update old parts of a behemoth code repository (note: paraphrasing a Google employee who worked on Google Drive platform).
Perhaps this is one reason Governments around the world do not find Google suitable for their Cloud Services needs?
A solution for Auditors is to replace in search strings any underscore with a whitespace or hyphen, then perhaps work out which is the correct match from a list of results.

How to use Universal Find and Replace? (ELI5)

I'm working on a project in a shared Google Drive folder where we recently learned we need to change some strings, that are found in all the documents, with slightly different strings. There are hundreds of files, and it'd be impossible to go through them all one by one, and after some looking I found a Universal Find and Replace script.
https://ctrlq.org/code/19926-universal-find-replace-in-google-drive
Problem is, I have little to no experience with code and even with the instructions given on the site, I have no clue what I have to do with the script. All of it is gibberish to me, and I'd be unbelievably grateful if someone could walk me through all of it.
Questions:
Where in the script do I specify the Drive folder in question and how do I specify it? The "folder path" thing has me even more confused, so if you can let me know where exactly I can find the needed info, that would be great.
Where do I specify the strings I need to replace? I can obviously tell that doc.replaceText has something to do with it, but the fact that it says "You can use regex too" makes me curious if there's anything else I need to change before that?
How should I make a copy of the script code and where in my Google Drive do I place the file?
If there's any other steps I might be overlooking, please mention those as well.
Also, will it be possible to replace more than one string in a single script? (i.e change all "red" to "blue" and change all "black" to "white")
Thank you all in advance, this might end up being a lifesaver?
You might want to look at Apps Script's Drive Service and Document Service to help you be more familiar about the classes and functions to be used.
Drive Service
This service allows scripts to create, find, and modify files and folders in Google Drive.
Document Service
This service allows scripts to create, access, and modify Google Docs files.
Creating a Folder
Using the sample code :
// Log the name of every folder in the user's Drive.
var folders = DriveApp.getFolders();
while (folders.hasNext()) {
var folder = folders.next();
Logger.log(folder.getName());
}
You can set
var newFolder = DriveApp.createFolder('My New Folder');
//To check if you successfully created a folder
Logger.log(newFolder.getId())
//To set sub folder under "My New Folder"
var id = newFolder.getId()
var subFolder = newFolder.createFolder('New Sub Folder')
2. Where do I specify the strings I need to replace? I can obviously tell that doc.replaceText has something to do with it, but the fact that it says "You can use regex too" makes me curious if there's anything else I need to change before that?
You can use findText(searchPattern, from)
Searches the contents of the element for the specified text pattern, starting from a given search result.
A subset of the JavaScript regular expression features are not fully supported, such as capture groups and mode modifiers.
The provided regular expression pattern is independently matched against each text block contained in the current element.
3. How should I make a copy of the script code and where in my Google Drive do I place the file?
You can use Apps Script Console to create your codes, this will be placed in you drive folder.
Lastly, here is a sample code that will change the color of the text:
var body = DocumentApp.getActiveDocument().getBody();
// Use editAsText to obtain a single text element containing
// all the characters in the document.
var text = body.editAsText();
// Insert text at the beginning of the document.
text.insertText(0, 'Inserted text.\n');
// Insert text at the end of the document.
text.appendText('\nAppended text.');
// Make the first half of the document blue.
text.setForegroundColor(0, text.getText().length / 2, '#00FFFF');
Hope it helps!

copying files using Google script

This might seem like very basic stuff, but can somebody tell me what the purpose of this [0]; after the ("myfile3") in the code below does? I got it from the Google developers page but there is no explanation as to what it does. I am new to GAS and Javascript and don't have a lot of programming experience but all I am trying to do is copy a file on from my root drive in Google drive and then move it to another folder. Then code below works sometimes, but then after a while I get an error that tells me: "File copyFile must be converted to a Google document first. (line 5, file "copy")".
Any help appreciated. (Sorry if it is a stupid question)
The code is:
function copyFile()
{
var file = DocsList.find("myfile3")[0];
var copy = file.makeCopy("myfile5");
}
from the documentation : find(query) : Returns an array of all the files in the container that contain the given string.
Find() searches the content of all the files, not their names.
That means that you have to choose which element of the array you want to open... using [0] means you take the first result.
It might be the file you're looking for but it is not sure at all...
To narrow your search to the filename you should simply iterate the returned array while testing each file's name and pick up the one you want.
it might be in a for loop like this :
var files = DocsList.find("myfile3");
for(var f=0;f<files.length;++f){if(files[f].getName()==query){var foundDocId=file[f].getId() ; break}
From there use the file ID to access your file as this one is unique (names are not in Google Docs).
as simple as that ;-)
I would suggest testing the DriveApp version of this function for two implicit reasons:
The DocsList service is deprecated and may be discontinued as the
DriveApp functions are fleshed out.
DriveApp is a little more agnostic
when it comes to filetypes, and may bypass your error.
Check out fileMakeCopy() in the Apps Script Documents for details.

Is there any easy way to get folderID based on a given path?

Box api is implemented to be RESTful. and most supported methods are based on ids, folder_id or file_id.
As a very beginning start point, a root folder id, 0, stands for the root directory /All Files/.
from there (fold_id = 0), I can loop through all sub folders and find folder id for certain target folder.
or I can send search request to "https://api.box.com/2.0/search?query=target_folder_name", and process the response to locate target folder.
The former approach may need multiple list-folder-item requests, and the latter approach might be slow because the search is not just for folder/file name but also for other attributes of folder/file and even file content.
I am wondering if there is an easy way to find folder id for certain folder with a given path, such as "/All Files/MyFolder_A/Project_11".
Thank you very much for any help.
To the best of my knowledge, walking the folder tree (as you've suggested) is still the fastest way to get the ID of a particular file/folder. (See also this question: Get file ID of a given path.)

Google Drive - Changes:list API - Detect changes at folder level

I'm testing out Google Drive 'Changes' API and have some questions.
Expectation:
I've folder tree structure under 'My Drive' with files in them. I would like to call the Changes:list API to detect if items have been added/edited/deleted within that specific folder id.
APIs Explorer tried: https://developers.google.com/drive/v2/reference/changes/list
Questions:
I don't see any option to pass a specific folder id to this API for getting the 'largestChangeId'. Looks like this api doesn't support the parm 'q'? Is it possible?
As an alternate solution, thought of storing the 'modifiedDate' attribute for that folder and use it for comparing next time. But, it's not getting updated when items are updated within that folder. Should it not work like in windows where folder modified date gets updated when its contents gets updated?
Would like to hear if it's possible to detect changes at folder level.
Thanks
[EDIT]
Solution that worked:
Use Files:list to list all.
selected fields: items/id,items/modifiedDate,items/parents/id,items/title
Get starting folder id ( e.g for 'MyRootFolder' using Title search)
Traverse through the sub-tree structure (linking parents:id and file Id) using recursive array search and get max modifiedDate and total file counts.
Store max modifiedDate and file counts in the app storage.
For subsequent calls, compare the new max modifiedDate with the stored and also compare total file counts with the stored. If either one doesn't match, then contents within 'MyRootFolder' has been updated.
This is not currently possible directly with the API -- sorry!
I think the best current solution would be to use the regular changes feed and filter results in your code to ones with the correct parents set.
drive.changes.list google drive API now allows users to pass the "startChangeId" parameter.
Im using the value I get for "largestChangeId" from the previous API result, So I can incrementally build the changes done by the user, avoiding the need to rebuild the entire tree.
how ever I'm surprised to see why they don't support the "includeDeleted" parameter together with "startChangeId" parameter.