Exclua dados com uma função de nuvem que pode ser chamada

A página descreve como usar uma função do Cloud que pode ser chamada para excluir dados. Depois de implantar essa função, você poderá chamá-la diretamente de seu aplicativo móvel ou site para excluir recursivamente documentos e coleções. Por exemplo, você pode usar esta solução para dar a usuários selecionados a capacidade de excluir coleções inteiras.

Para conhecer outras maneiras de excluir coleções, consulte Excluir dados .

Solução: excluir dados com uma função do Cloud que pode ser chamada

A exclusão de coleções inteiras de um aplicativo móvel com recursos limitados pode ser difícil de implementar pelos seguintes motivos:

  • Não há operação que exclua atomicamente uma coleção.
  • A exclusão de um documento não exclui os documentos de suas subcoleções.
  • Se seus documentos tiverem subcoleções dinâmicas, pode ser difícil saber quais dados excluir para um determinado caminho.
  • A exclusão de uma coleção de mais de 500 documentos requer diversas operações de gravação em lote ou centenas de exclusões únicas.
  • Em muitos aplicativos, não é apropriado dar permissão aos usuários finais para excluir coleções inteiras.

Felizmente, você pode escrever uma Cloud Function que pode ser chamada para executar exclusões seguras e de alto desempenho de coleções ou árvores de coleção inteiras. A Cloud Function abaixo implementa uma função que pode ser chamada , o que significa que ela pode ser chamada diretamente do seu aplicativo móvel ou site, como faria para uma função local.

Para implantar a função e experimentar uma demonstração, consulte o código de exemplo .

Função de nuvem

A Cloud Function abaixo exclui uma coleção e todos os seus descendentes.

Em vez de implementar sua própria lógica de exclusão recursiva para sua função do Cloud, você pode aproveitar as vantagens do comando firestore:delete na interface de linha de comando (CLI) do Firebase. Você pode importar qualquer função da CLI do Firebase para seu aplicativo Node.js usando o pacote firebase-tools .

A CLI do Firebase usa a API REST do Cloud Firestore para encontrar todos os documentos no caminho especificado e excluí-los individualmente. Esta implementação não requer conhecimento da hierarquia de dados específica do seu aplicativo e até mesmo encontrará e excluirá documentos "órfãos" que não possuem mais um pai.

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

Invocação do cliente

Para chamar a função, obtenha uma referência à função no SDK do Firebase e passe os parâmetros necessários:

Rede
/**
 * 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
Observação: este produto não está disponível em destinos watchOS e App Clip.
    // Snippet not yet written
    
Objetivo-C
Observação: este produto não está disponível em destinos watchOS e 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
                    // ...
                }
            });
}

Ao usar o SDK do cliente para funções de nuvem que podem ser chamadas, o estado de autenticação dos usuários e o parâmetro path são transmitidos perfeitamente para a função remota. Quando a função for concluída, o cliente receberá um retorno de chamada com o resultado ou uma exceção. Para saber como chamar uma função de nuvem do Android, Apple ou outra plataforma, leia a documentação .

Limitações

A solução mostrada acima demonstra a exclusão de coleções de uma função que pode ser chamada, mas você deve estar ciente das seguintes limitações:

  • Consistência – o código acima exclui um documento de cada vez. Se você fizer uma consulta enquanto houver uma operação de exclusão em andamento, seus resultados poderão refletir um estado parcialmente completo, onde apenas alguns documentos direcionados serão excluídos. Também não há garantia de que as operações de exclusão serão bem-sucedidas ou falharão de maneira uniforme; portanto, esteja preparado para lidar com casos de exclusão parcial.
  • Tempos limite - a função acima está configurada para funcionar por no máximo 540 segundos antes de atingir o tempo limite. O código de exclusão pode excluir 4.000 documentos por segundo, na melhor das hipóteses. Se você precisar excluir mais de 2.000.000 de documentos, considere executar a operação em seu próprio servidor para que o tempo limite não expire. Para obter um exemplo de como excluir uma coleção do seu próprio servidor, consulte Excluir coleções .