Supprimer des données avec une fonction Cloud appelable

Cette page décrit comment utiliser une fonction Cloud appelable pour supprimer des données. Une fois cette fonction déployée, vous pouvez l'appeler directement depuis votre application mobile ou votre site Web pour supprimer de manière récursive des documents et des collections. Par exemple, vous pouvez utiliser cette solution pour permettre à certains utilisateurs de supprimer des collections entières.

Pour découvrir d'autres méthodes de suppression des collections, consultez la page Supprimer des données.

Solution : supprimer des données avec une fonction Cloud appelable

La suppression de collections entières d'une application mobile à ressources limitées peut s'avérer difficile pour les raisons suivantes :

  • Aucune opération ne supprime de manière atomique une collection.
  • La suppression d'un document ne supprime pas les documents de ses sous-collections.
  • Si vos documents comportent des sous-collections dynamiques, il peut être difficile de savoir quelles données supprimer pour un chemin donné.
  • La suppression d'une collection de plus de 500 documents nécessite plusieurs opérations d'écriture par lot ou des centaines de suppressions uniques.
  • Dans de nombreuses applications, il n'est pas approprié de donner aux utilisateurs finaux l'autorisation de supprimer des collections entières.

Heureusement, vous pouvez écrire une fonction Cloud appelable pour exécuter des suppressions sécurisées et performantes de collections entières ou d'arbres de collection. La fonction Cloud ci-dessous met en œuvre une fonction appelable, ce qui signifie qu'elle peut être appelée directement depuis votre application mobile ou votre site Web, de la même manière qu'une fonction locale.

Pour déployer la fonction et essayer une version de démonstration, consultez l'exemple de code.

Fonction Cloud

La fonction Cloud ci-dessous supprime une collection et tous ses descendants.

Au lieu de mettre en œuvre votre propre logique de suppression récursive pour votre fonction Cloud, vous pouvez tirer parti de la commande firestore:delete de l'interface de ligne de commande (CLI) Firebase. Vous pouvez importer n'importe quelle fonction de la CLI Firebase dans une application Node.js propre à l'aide du package firebase-tools.

La CLI Firebase utilise l'API REST Cloud Firestore pour rechercher tous les documents dans le chemin spécifié et les supprimer individuellement. Cette mise en œuvre ne nécessite aucune connaissance de la hiérarchie de données propre à votre application et permet même de rechercher et de supprimer les documents "orphelins" qui n'ont plus de parent.

Node.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 
    };
  });

Invocation de client

Pour appeler la fonction, obtenez une référence à la fonction du SDK Firebase et transmettez les paramètres requis :

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);
        });
}
Swift
Remarque : Ce produit n'est pas disponible sur les cibles watchOS et App Clip.
    // Snippet not yet written
    
Objective-C
Remarque : Ce produit n'est pas disponible sur les cibles watchOS et App Clip.
    // Snippet not yet written
    

Kotlin

/**
 * 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
                    // ...
                }
            });
}

En utilisant le SDK du client pour les fonctions Cloud appelables, l'état d'authentification des utilisateurs et le paramètre path sont transmis en toute transparence à la fonction distante. Lorsque la fonction est terminée, le client reçoit un rappel avec le résultat ou une exception. Pour savoir comment appeler une fonction Cloud depuis Android, Apple ou une autre plate-forme, lisez la documentation.

Limites

La solution ci-dessus illustre la suppression de collections à partir d'une fonction appelable, mais vous devez tenir compte des limites suivantes :

  • Cohérence : le code ci-dessus supprime les documents un par un. Si vous lancez une requête alors qu'une opération de suppression est en cours, vos résultats peuvent indiquer un état partiellement complet où seuls certains documents ciblés sont supprimés. Il n'existe aucune garantie que les opérations de suppression aboutiront ou échoueront de manière uniforme. Soyez donc prêt à gérer les cas de suppression partielle.
  • Expiration de délai : la fonction ci-dessus est configurée pour s'exécuter pendant 540 secondes au maximum avant expiration du délai. Dans le meilleur des cas, le code de suppression peut supprimer 4 000 documents par seconde. Si vous devez supprimer plus de 2 000 000 documents, vous pouvez envisager d'exécuter l'opération sur votre propre serveur afin de ne pas interrompre le traitement. Pour obtenir un exemple de suppression d'une collection depuis votre propre serveur, consultez la section Supprimer des collections.
  • Si vous supprimez un grand nombre de documents, le visionneuse de données de la console Google Cloud peut se charger lentement ou renvoyer une erreur de délai avant expiration.