Eliminar datos con una función de nube invocable

La página describe cómo utilizar una función de nube invocable para eliminar datos. Una vez que implemente esta función, puede llamarla directamente desde su aplicación móvil o sitio web para eliminar documentos y colecciones de forma recursiva. Por ejemplo, puede utilizar esta solución para brindar a usuarios seleccionados la posibilidad de eliminar colecciones completas.

Para conocer otras formas de eliminar colecciones, consulte Eliminar datos .

Solución: eliminar datos con una función en la nube invocable

Eliminar colecciones enteras de una aplicación móvil con recursos limitados puede resultar difícil de implementar por los siguientes motivos:

  • No existe ninguna operación que elimine atómicamente una colección.
  • Eliminar un documento no elimina los documentos de sus subcolecciones.
  • Si sus documentos tienen subcolecciones dinámicas, puede resultar difícil saber qué datos eliminar para una ruta determinada.
  • Eliminar una colección de más de 500 documentos requiere múltiples operaciones de escritura por lotes o cientos de eliminaciones únicas.
  • En muchas aplicaciones, no es apropiado otorgar permiso a los usuarios finales para eliminar colecciones enteras.

Afortunadamente, puede escribir una función en la nube invocable para ejecutar eliminaciones seguras y eficaces de colecciones o árboles de colecciones completos. La siguiente función en la nube implementa una función invocable , lo que significa que se puede llamar directamente desde su aplicación móvil o sitio web como lo haría con una función local.

Para implementar la función y probar una demostración, consulte el código de muestra .

Función de nube

La función de nube siguiente elimina una colección y todos sus descendientes.

En lugar de implementar su propia lógica de eliminación recursiva para su función en la nube, puede aprovechar el comando firestore:delete en la interfaz de línea de comandos (CLI) de Firebase. Puede importar cualquier función de Firebase CLI a su aplicación Node.js utilizando el paquete firebase-tools .

Firebase CLI utiliza la API REST de Cloud Firestore para buscar todos los documentos en la ruta especificada y eliminarlos individualmente. Esta implementación no requiere conocimiento de la jerarquía de datos específica de su aplicación e incluso encontrará y eliminará documentos "huérfanos" que ya no tienen un padre.

Nodo.js

/**
 * Initiate a recursive delete of documents at a given path.
 * 
 * The calling user must be authenticated and have the custom "admin" attribute
 * set to true on the auth token.
 * 
 * This delete is NOT an atomic operation and it's possible
 * that it may fail after only deleting some documents.
 * 
 * @param {string} data.path the document or collection path to delete.
 */
exports.recursiveDelete = functions
  .runWith({
    timeoutSeconds: 540,
    memory: '2GB'
  })
  .https.onCall(async (data, context) => {
    // Only allow admin users to execute this function.
    if (!(context.auth && context.auth.token && context.auth.token.admin)) {
      throw new functions.https.HttpsError(
        'permission-denied',
        'Must be an administrative user to initiate delete.'
      );
    }

    const path = data.path;
    console.log(
      `User ${context.auth.uid} has requested to delete path ${path}`
    );

    // Run a recursive delete on the given document or collection path.
    // The 'token' must be set in the functions config, and can be generated
    // at the command line by running 'firebase login:ci'.
    await firebase_tools.firestore
      .delete(path, {
        project: process.env.GCLOUD_PROJECT,
        recursive: true,
        force: true,
        token: functions.config().fb.token
      });

    return {
      path: path 
    };
  });

Invocación de cliente

Para llamar a la función, obtenga una referencia a la función del SDK de Firebase y pase los parámetros requeridos:

Web
/**
 * Call the 'recursiveDelete' callable function with a path to initiate
 * a server-side delete.
 */
function deleteAtPath(path) {
    var deleteFn = firebase.functions().httpsCallable('recursiveDelete');
    deleteFn({ path: path })
        .then(function(result) {
            logMessage('Delete success: ' + JSON.stringify(result));
        })
        .catch(function(err) {
            logMessage('Delete failed, see console,');
            console.warn(err);
        });
}
Rápido
Nota: Este producto no está disponible en destinos watchOS y App Clip.
    // Snippet not yet written
    
C objetivo
Nota: Este producto no está disponible en destinos watchOS y App Clip.
    // Snippet not yet written
    

Kotlin+KTX

/**
 * Call the 'recursiveDelete' callable function with a path to initiate
 * a server-side delete.
 */
fun deleteAtPath(path: String) {
    val deleteFn = Firebase.functions.getHttpsCallable("recursiveDelete")
    deleteFn.call(hashMapOf("path" to path))
        .addOnSuccessListener {
            // Delete Success
            // ...
        }
        .addOnFailureListener {
            // Delete Failed
            // ...
        }
}

Java

/**
 * Call the 'recursiveDelete' callable function with a path to initiate
 * a server-side delete.
 */
public void deleteAtPath(String path) {
    Map<String, Object> data = new HashMap<>();
    data.put("path", path);

    HttpsCallableReference deleteFn =
            FirebaseFunctions.getInstance().getHttpsCallable("recursiveDelete");
    deleteFn.call(data)
            .addOnSuccessListener(new OnSuccessListener<HttpsCallableResult>() {
                @Override
                public void onSuccess(HttpsCallableResult httpsCallableResult) {
                    // Delete Success
                    // ...
                }
            })
            .addOnFailureListener(new OnFailureListener() {
                @Override
                public void onFailure(@NonNull Exception e) {
                    // Delete failed
                    // ...
                }
            });
}

Al utilizar el SDK del cliente para funciones de nube invocables, el estado de autenticación de los usuarios y el parámetro path se pasan sin problemas a la función remota. Cuando se complete la función, el cliente recibirá una devolución de llamada con el resultado o una excepción. Para obtener información sobre cómo llamar a una función en la nube desde Android, Apple u otra plataforma, lea la documentación .

Limitaciones

La solución que se muestra arriba demuestra cómo eliminar colecciones de una función invocable, pero debes tener en cuenta las siguientes limitaciones:

  • Coherencia : el código anterior elimina los documentos uno a la vez. Si realiza la consulta mientras hay una operación de eliminación en curso, sus resultados pueden reflejar un estado parcialmente completo en el que solo se eliminan algunos documentos específicos. Tampoco hay garantía de que las operaciones de eliminación tengan éxito o fallen de manera uniforme, así que esté preparado para manejar casos de eliminación parcial.
  • Tiempos de espera : la función anterior está configurada para ejecutarse durante un máximo de 540 segundos antes de que expire el tiempo de espera. El código de eliminación puede eliminar 4000 documentos por segundo en el mejor de los casos. Si necesita eliminar más de 2.000.000 de documentos, debería considerar ejecutar la operación en su propio servidor para que no se agote el tiempo de espera. Para ver un ejemplo de cómo eliminar una colección de su propio servidor, consulte Eliminar colecciones .