Solución:
EDITAR: abril de 2020 Google ha anunciado que los archivos de padres múltiples se deshabilitarán a partir de septiembre de 2020. Esto altera la narrativa a continuación y significa que la opción 2 ya no es una opción. Podría ser posible implementar la Opción 2 usando atajos. Actualizaré esta respuesta más a medida que pruebe las nuevas restricciones / características
Todos estamos acostumbrados a la idea de carpetas (también conocidas como directorios) en Windows / nix, etc. En el mundo real, una carpeta es un contenedor en el que se colocan los documentos. También es posible colocar carpetas más pequeñas dentro de carpetas más grandes. Por lo tanto, se puede pensar que la carpeta grande contiene todos los documentos dentro de sus carpetas secundarias más pequeñas.
Sin embargo, en Google Drive, una carpeta es NO un contenedor, tanto que en la primera versión de Google Drive, ni siquiera se llamaban Carpetas, se llamaban Colecciones. Una carpeta es simplemente un archivo con (a) sin contenido y (b) un tipo de mimo especial (application / vnd.google-apps.folder). La forma en que se utilizan las carpetas es exactamente de la misma forma que se utilizan las etiquetas (también conocidas como etiquetas). La mejor manera de entender esto es considerar GMail. Si observa la parte superior de un elemento de correo abierto, verá dos iconos. Una carpeta con la información sobre herramientas “Mover a” y una etiqueta con la información sobre herramientas “Etiquetas”. Haga clic en cualquiera de estos y aparecerá el mismo cuadro de diálogo y se trata de etiquetas. Sus etiquetas se enumeran en el lado izquierdo, en una pantalla de árbol que se parece mucho a las carpetas. Es importante destacar que un elemento de correo puede tener varias etiquetas, o podría decirse que un elemento de correo puede estar en varias carpetas. Las carpetas de Google Drive funcionan exactamente de la misma manera que las etiquetas de GMail.
Habiendo establecido que una Carpeta es simplemente una etiqueta, no hay nada que le impida organizar sus etiquetas en una jerarquía que se asemeja a un árbol de carpetas; de hecho, esta es la forma más común de hacerlo.
Ahora debería quedar claro que un archivo (llamémoslo MyFile) en la carpeta A2b NO es un hijo o nieto de la carpeta A. Es simplemente un archivo con una etiqueta (confusamente llamada Padre) de “carpetaA2b”.Bien, entonces, ¿cómo obtengo todos los archivos “bajo” la carpeta A?
Alternativa 1. Recurrencia
La tentación sería listar los hijos de la carpeta A, para cualquier hijo que sea carpeta, enumerar recursivamente a sus hijos, enjuagar, repetir. En un número muy reducido de casos, este podría ser el mejor enfoque, pero para la mayoría tiene los siguientes problemas: –
- Lamentablemente, lleva mucho tiempo hacer un viaje de ida y vuelta al servidor para cada subcarpeta. Por supuesto, esto depende del tamaño de su árbol, por lo que si puede garantizar que el tamaño de su árbol es pequeño, podría estar bien.
Alternativa 2. El padre común
Esto funciona mejor si su aplicación está creando todos los archivos (es decir, si está utilizando el alcance de drive.file). Además de la jerarquía de carpetas anterior, cree una carpeta principal ficticia llamada “MyAppCommonParent”. A medida que crea cada archivo como hijo de su carpeta particular, también lo convierte en hijo de MyAppCommonParent. Esto se vuelve mucho más intuitivo si recuerda pensar en las carpetas como etiquetas. Ahora puede recuperar fácilmente todos los descdendants simplemente consultando MyAppCommonParent in parents
.
Alternativa 3. Primero las carpetas
Empiece por obtener todas las carpetas. Sí, todos ellos. Una vez que los tenga todos en la memoria, puede rastrear las propiedades de sus padres y construir su estructura de árbol y una lista de ID de carpeta. Entonces puedes hacer una sola files.list?q='folderA' in parents or 'folderA1' in parents or 'folderA1a' in parents...
. Con esta técnica puede obtener todo en dos llamadas http.
El pseudocódigo para la opción 3 es un poco como …
// get all folders from Drive files.list?q=mimetype=application/vnd.google-apps.folder and trashed=false&fields=parents,name // store in a Map, keyed by ID // find the entry for folderA and note the ID // find any entries where the ID is in the parents, note their IDs // for each such entry, repeat recursively // use all of the IDs noted above to construct a ... // files.list?q='folderA-ID' in parents or 'folderA1-ID' in parents or 'folderA1a-ID' in parents...
La alternativa 2 es la más eficaz, pero solo funciona si tiene el control de la creación de archivos. La Alternativa 3 es generalmente más eficiente que la Alternativa 1, pero puede haber ciertos tamaños de árboles pequeños donde 1 es mejor.
Compartiendo una solución de Python con la excelente Alternativa 3 por @pinoyyid, arriba, en caso de que sea útil para alguien. No soy desarrollador, por lo que probablemente no sea un pitón … pero funciona, solo hace 2 llamadas a la API y es bastante rápido.
- Obtenga una lista maestra de todas las carpetas en una unidad.
- Pruebe si la carpeta para buscar es un padre (es decir, tiene subcarpetas).
- Repita las subcarpetas de las pruebas de carpeta para buscar si ellos también son padres.
- Cree una consulta de archivo de Google Drive con uno
'
segmento por subcarpeta encontrado.' in parents
Curiosamente, Google Drive parece tener un límite estricto de 599 '
segmentos por consulta, por lo que si su carpeta para buscar tiene más subcarpetas que esta, debe dividir la lista.
FOLDER_TO_SEARCH = '123456789' # ID of folder to search
DRIVE_ID = '654321' # ID of shared drive in which it lives
MAX_PARENTS = 500 # Limit set safely below Google max of 599 parents per query.
def get_all_folders_in_drive():
"""
Return a dictionary of all the folder IDs in a drive mapped to their parent folder IDs (or to the
drive itself if a top-level folder). That is, flatten the entire folder structure.
"""
folders_in_drive_dict =
page_token = None
max_allowed_page_size = 1000
just_folders = "trashed = false and mimeType = 'application/vnd.google-apps.folder'"
while True:
results = drive_api_ref.files().list(
pageSize=max_allowed_page_size,
fields="nextPageToken, files(id, name, mimeType, parents)",
includeItemsFromAllDrives=True, supportsAllDrives=True,
corpora='drive',
driveId=DRIVE_ID,
pageToken=page_token,
q=just_folders).execute()
folders = results.get('files', [])
page_token = results.get('nextPageToken', None)
for folder in folders:
folders_in_drive_dict[folder['id']] = folder['parents'][0]
if page_token is None:
break
return folders_in_drive_dict
def get_subfolders_of_folder(folder_to_search, all_folders):
"""
Yield subfolders of the folder-to-search, and then subsubfolders etc. Must be called by an iterator.
:param all_folders: The dictionary returned by :meth:`get_all_folders_in-drive`.
"""
temp_list = [k for k, v in all_folders.items() if v == folder_to_search] # Get all subfolders
for sub_folder in temp_list: # For each subfolder...
yield sub_folder # Return it
yield from get_subfolders_of_folder(sub_folder, all_folders) # Get subsubfolders etc
def get_relevant_files(self, relevant_folders):
"""
Get files under the folder-to-search and all its subfolders.
"""
relevant_files =
chunked_relevant_folders_list = [relevant_folders[i:i + MAX_PARENTS] for i in
range(0, len(relevant_folders), MAX_PARENTS)]
for folder_list in chunked_relevant_folders_list:
query_term = ' in parents or '.join('"0"'.format(f) for f in folder_list) + ' in parents'
relevant_files.update(get_all_files_in_folders(query_term))
return relevant_files
def get_all_files_in_folders(self, parent_folders):
"""
Return a dictionary of file IDs mapped to file names for the specified parent folders.
"""
files_under_folder_dict =
page_token = None
max_allowed_page_size = 1000
just_files = f"mimeType != 'application/vnd.google-apps.folder' and trashed = false and (parent_folders)"
while True:
results = drive_api_ref.files().list(
pageSize=max_allowed_page_size,
fields="nextPageToken, files(id, name, mimeType, parents)",
includeItemsFromAllDrives=True, supportsAllDrives=True,
corpora='drive',
driveId=DRIVE_ID,
pageToken=page_token,
q=just_files).execute()
files = results.get('files', [])
page_token = results.get('nextPageToken', None)
for file in files:
files_under_folder_dict[file['id']] = file['name']
if page_token is None:
break
return files_under_folder_dict
if __name__ == "__main__":
all_folders_dict = get_all_folders_in_drive() # Flatten folder structure
relevant_folders_list = [FOLDER_TO_SEARCH] # Start with the folder-to-archive
for folder in get_subfolders_of_folder(FOLDER_TO_SEARCH, all_folders_dict):
relevant_folders_list.append(folder) # Recursively search for subfolders
relevant_files_dict = get_relevant_files(relevant_folders_list) # Get the files
Aquí puedes ver las reseñas y valoraciones de los lectores
Si para ti ha sido útil este post, sería de mucha ayuda si lo compartieras con más seniors y nos ayudes a extender nuestro contenido.