Merge folder with the same name in google drive using google script - google-apps-script

Who knows how to merge folder with the same name in google drive using google script?
Step 01: Find if any duplicate folder in the root-Folder;
Step 02: If yes, choose one folder as main-folder, and then move all files in the other folder(with the same name) to this main-folder;
Step 03: Delete the other folder(with the same name).
Many thanks in advance.
Merge Folder with the same name under the same Folder

My approach:
Take parent folder in which you want to check for folders with same name
Loop over all subfolders and get their names
Find all folders within parent folder with each found folder name
Specify first iteration for given folderName as destination folder
If there is more than one folder with given name, move all files and folders from this folder to destination folder and trash that folder
Try this:
I have succesfully tested this function on some junk data.
function mergeDuplicateFolders() {
var parentFolder = DriveApp.getFolderById('{paste your folder ID here}'); //parent folder which will be scanned for duplicates
var childFolderIterator = parentFolder.getFolders(); //all folders within parent folder
//iteration over all folders in parent directory
while (childFolderIterator.hasNext()) {
var childFolder = childFolderIterator.next();
var childFolderName = childFolder.getName();
var childSameNameIterator = parentFolder.getFoldersByName(childFolderName);
//just check if folder with givn name exist (there should be at least one)
if(childSameNameIterator.hasNext()) {
var destFolder = childSameNameIterator.next();
//iteration over 2nd and all other folders with given name
while (childSameNameIterator.hasNext()) {
var toMergeFolder = childSameNameIterator.next();
var filesToMove = toMergeFolder.getFiles();
var foldersToMove = toMergeFolder.getFolders()
//iteration over all files
while (filesToMove.hasNext()) {
var file = filesToMove.next();
moveFile(file, destFolder);
}
//iteration over all subfolders
while (foldersToMove.hasNext()) {
var folder = foldersToMove.next();
moveFolder(folder, destFolder);
}
//trashes empty folder
toMergeFolder.setTrashed(true);
}
}
}
}
//custom function which removes all parents from speciefied file and adds file to new folder
function moveFile(file, destFolder) {
var currentParents = file.getParents();
while (currentParents.hasNext()) { // be careful, this loop will remove all parents from the file... if you want to have this file in multiple folders you should add if statement to remove it only from specified folder
var currentParent = currentParents.next();
currentParent.removeFile(file);
}
destFolder.addFile(file);
Logger.log("File moved to " + destFolder.getName());
}
//custom function which removes all parents from speciefied folder and adds that folder to new one
function moveFolder(folder, destFolder) {
var currentParents = folder.getParents();
while (currentParents.hasNext()) { // be careful, this loop will remove all parents from the folder... if you want to have this folder in multiple folders you should add if statement to remove it only from specified folder
var currentParent = currentParents.next();
currentParent.removeFolder(folder);
}
destFolder.addFolder(folder);
Logger.log("Folder moved to " + destFolder.getName());
}
Your application:
You can of course edit first two lines of this function and add parentFolderId as parameter of that function. Then you can use this function in your own iteration and check multiple folders for duplicates.
function mergeDuplicateFolders(parentFolderId) {
var parentFolder = DriveApp.getFolderById(parentFolderId);
//...continue with the code from above
Warnings
Be careful. In Google Drive you can have one file in multiple folders.
This code will remove files (in folders with same name) from all
parent folders and moves them only in one. If you prefere removing it
only from the folder with same name, you need to add some if statement
in moveFolder() and moveFile() functions.
Google script allows to run custom function only for (approx.) 6 minutes. If you have large amout of folders to check, you should make some workaround. You can add e.g. execution time limit. Example is here: Prevent Google Scripts from Exceeding the Maximum Execution Time Limit
EDIT:
Of course there is much simpler way to remove file only frome merged folder... Remove both custom functions and edit both iterations this way... I didn't realize it first.
//iteration over all files
while (filesToMove.hasNext()) {
var file = filesToMove.next();
toMergeFolder.removeFile(file);
destFolder.addFile(file);
}
//iteration over all subfolders
while (foldersToMove.hasNext()) {
var folder = foldersToMove.next();
toMergeFolder.removeFolder(folder);
destFolder.addFolder(folder);
}

Class Folder, currently, doesn't have existing method to move files from one folder in Google Drive to another.
And as far as I know, there is an existing issue on Seeing duplicate files after sync on desktop Drive version 1.14. However, you may follow the given workaround in the forum as follows:
Step 01:
How to Find duplicates files (by name and/or size) in a specific folder of my google drive
Step 02:
How do I copy & move a file to a folder in Google Apps Script?
Step 03: You can use removeFolder(child) method from Class Folder, which can only be used to remove a given folder from a current folder.
I hope that helps.

Related

Google apps script to clear folder given a folder_id not working (isTrashed not deleting files)

I am trying to write a google apps script to clear a given folder given the folder ID but the function is not behaving as expected. It runs without an error but it seems isTrashed() does not delete all files? I have looked at the documentation but can't seem to figure out how to get all the files in a folder to be deleted.
function clearFolder(folderId) {
// Get the folder
var folder = DriveApp.getFolderById(folderId);
Logger.log("clearFolder on folder: %s",folder.getName())
// Get all the files in the folder
var files = folder.getFiles();
// Iterate through the files and delete them
while (files.hasNext()) {
var file = files.next();
Logger.log("clearFolder deleting file named '%s'",file.getName())
file.isTrashed();
}
}
The file.isTrashed() method does not delete files. It determines whether the file is in the trash, and returns a true/false value that is ignored by the code you quote.
To delete files, use file.setTrashed(true).

How do I retrieve and store files and folders structure in a google spreadsheet using apps script?

I know this question has been asked before, but I am trying to go a bit deeper in the problem. I have this apps script code I have taken online and I am using it in a google spreadsheet, to scan for a list of folders.
In short, I have a (shared) folder structure with most likely over 1000 sub-folders, which contain sub-subfolders, that looks similar to this:
MAIN FOLDER
FOLDER 1
FILE 1.1
SUBFOLDER 1.A
SUBFILE 1.A.2
SUBFILE 1.A.3
FOLDER 2
FILE 2.1
SUBFOLDER 2.A
SUBFILE 2.A.2
SUBFILE 2.A.3
FOLDER 3
FILE 3.1
SUBFOLDER 3.A
SUBFILE 3.A.2
SUBFILE 3.A.3
...
I am trying to fix 2 things:
1) My function obviously breaks when running because there are too many folders and files. I don't think it's due to the limit of rows in a spreadsheet. So, ideally, I would have to manually batch 200 folders in the main folder, run the function, and re-iterate. Any hints how to avoid that, and how to potentially, dump temporary results in a first spreadsheet and create a new spreadsheet if it's a caching problem?
2) I am not able to retrieve subfolders details and the details of the files it contains. Can anyone help adapt the code to go deeper in the folder hierarchy? Do I need some kind of loop function here?
With the code provided hereunder which I have used and tested a few times, I can only retrieve the folders 1,2,3 and files 1.1, 2.1, 3.1...but not subfolders or subfiles.
Fixing this function, would save me weeks of manual work. Any help is welcomed. Thanks in advance for your help.
function getAndListFilesInFolder() {
var arr,f,file,folderName,subFolders,id,mainFolder,name,own,sh,thisSubFolder,url;
sh = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0];
sh.getRange(1, 1, 100, 10).clear({contentsOnly: true})
id = "FOLDER ID HERE";
arr = [["FILE NAME", "URLs", "OWNER","FOLDER"]];
mainFolder = DriveApp.getFolderById(id);
subFolders = mainFolder.getFolders();
folderName = mainFolder.getName();
f = mainFolder.getFiles();
while (f.hasNext()) {
file = f.next();
name = file.getName()
url = file.getUrl()
own = file.getOwner().getName()
arr.push([name, url, own, folderName]);
};
while (subFolders.hasNext()) {
thisSubFolder = subFolders.next();
f = thisSubFolder.getFiles();
folderName = thisSubFolder.getName();
while (f.hasNext()) {
file = f.next();
name = file.getName()
url = file.getUrl()
own = file.getOwner().getName()
arr.push([name, url, own,folderName]);
};
};
sh.getRange(1,1, arr.length, arr[0].length).setValues(arr);
sh.getRange(2,1, arr.length, arr[0].length).sort(1);
//var second = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet2")
//second.activate()
}
The reason you aren't seeing any of the subfolders is because you are not actually adding them to your array (arr) at any time.
What you really need here is is to write a recursive function, which receives a folder and returns itself plus it's file's details details in an array. When you encounter a folder, you pass that folder back to the same function.
Investigate recursion and recursive functions.
Here is a brief example you could expand, it'll need some tweaking since I'm writing this off the top of my head:
function getFilesFromFolder(folder){
var arr = [];
arr.push([folder.getName(),folder.getUrl(),folder.getOwner().getName()])
var subfolders = folder.getFolders();
var files = folder.getFiles():
while(files.hasNext()){
arr.push(/*file details*/);
}
//recurse into subfolders here.
while(subFolders.hasNext()){
arr.concat(getFilesFromFolder(subFolders.next()); //notice how we call the function from within itself.
}
return arr;
}

Moving a folder (with its contents) with DriveApp

DriveApp does not have a "move"-function (as of today). How can I move this folder (with all its contents as it is)?
I wish to move the source_folder (which currently resides in parent_folder)
var source_Folder = DriveApp.getFolderById(source_id);
var parent_Folder = DriveApp.getFolderById(parent_id);
and put it inside target_folder:
var target_folder = DriveApp.getFolderById(target_id);
I already have source_id,parent_id and target_id
I looked around a bit and there is similar questions/answer to this problem. I made this to (hopefully) make it easy for others with the same problem.
"Folders" in Google Drive work pretty much the same way as "Labels" in
Gmail.
You may add a folder multiple places in Google Drive. It will still be only one folder (not a copy) so its contents are available from all the places where you added the folder.
To simulate moving the source_folder, you
can:
1) first add the source_folder to the target_folder
target_folder.addFolder(source_folder);
2) remove the source_folder from its parent.
parent_folder.removeFolder(source_folder);
full example code: (note: you need the folder ID's)
function move_folder() { // id looks like this: 1XqH79csKkPMvTsCxMUzkkpURETKHJ
var source_id = "[insert_folder_id]"; // folder you wish to move
var parent_id = "[insert_folder_id]"; // where the folder is currently
var target_id = "[insert_folder_id]"; // where you want to put the folder
var source_Folder = DriveApp.getFolderById(source_id);
var parent_Folder = DriveApp.getFolderById(parent_id);
var target_Folder = DriveApp.getFolderById(target_id);
target_folder.addFolder(source_folder); // source_folder now 2 places
parent_folder.removeFolder(source_folder); // cleanup
}
how to get folder_id.
right-clicking on a folder and getting a shareable link. (the random-looking string after id=)
Get ID of newly created Folder in Google Apps Script
parent folder: DriveApp parent folder
a good answer is also found here: Implement a folder move function in Google Dirve

new to scripting I'm looking to give permissions to folders I have to multiple individual users via Google Apps Script

what I need to do is lets say I have 100 users and I need to give them rights to folders that I have on my google drive each person will have there own folder that only they can see and I can see .... so I would create a folder for bob called work and I need to give him rights to the folder same for sue etc. bob and sue can not see each others work folder but I can see it
the only thing I can find close is
function SetRights() {
var folder = DriveApp.createFolder('WORK');
folder.setSharing(DriveApp.Access.DOMAIN, DriveApp.Permission.EDIT)
}
but the folders are all-ready created and I don't want to give rights to the whole domain.
You can fetch an existing folder using DriveApp.getFoldersByName() to return a FolderIterator. Loop over the folders to add viewer(s) and editor(s) to each folder with the folder.addEditor() and folder.addViewer() methods.
function AddUsersToFolder() {
// get folders (FolderIterator) by name, should probably be dynamic
var folders = DriveApp.getFoldersByName('FOLDERNAME');
// loop over all the folders
while (folders.hasNext()) {
// get the current folder from the iterator
var folder = folders.next();
// add viewer(s) and editor(s), should also be dynamic
folder.addEditor('editor#domain.com');
folder.addViewer('viewer#domain.com');
}
}

How to delete/overwrite CSV file using google apps script?

My google apps script imports a csv file [test.csv] into a new tab, manipulates some values, then saves the manipulated tab as a csv file [test.csv]. When it saves the new version, it simply makes another copy [test(1).csv]. I wish instead to overwrite the previous file (or delete the old one then export/write the new version.) Help please?
I am using reference code from the Interacting With Docs List Tutorial
I know this is an old question, but much of the information in the accepted answer has been deprecated by Google since then. DocsList is gone, as are the clear() and append() methods on a file object.
I use the following function to create or overwrite a file:
// Creates or replaces an existing file
function updateFile (folder, filename, data) {
try {
// filename is unique, so we can get first element of iterator
var file = folder.getFilesByName(filename).next()
file.setContent(data)
} catch(e) {
folder.createFile(filename, data)
}
}
For reference, here's some code for doing the same for a folder. It assumes we're operating in the parent folder of the current sheet and want a folder
object for a new or existing folder there.
// Get folder under current folder. Create it if it does not exist
function getOrCreateFolder(csvFolderName) {
var thisFileId = SpreadsheetApp.getActive().getId();
var thisFile = DriveApp.getFileById(thisFileId);
var parentFolder = thisFile.getParents().next();
try {
// csvFolderName is unique, so we can get first element of iterator
var folder = parentFolder.getFoldersByName(csvFolderName).next();
// asking for the folder's name ensures we get an error if the
// folder doesn't exist. I've found I don't necessarily catch
// an error from getFoldersByName if csvFolderName doesn't exist.
fname = folder.getName()
} catch(e) {
var folder = parentFolder.createFolder(csvFolderName);
}
return folder
}
You could do DocsList.find(fileName) which gives you a list of files that have that name. If file names are unique, then you can just do var file = DocsList.find(fileName)[0].
If you are a Google Apps user, you can use file.clear() to remove all the contents of the old file, and then file.append() to insert all of the new contents.
Otherwise, you will have to file.setTrashed(true) and then DocsList.createFile() to make the new one.