Menghapus data dengan Cloud Function Callable

Halaman ini menjelaskan cara menggunakan Cloud Function callable untuk menghapus data. Setelah men-deploy fungsi ini, Anda dapat memanggilnya langsung dari aplikasi seluler atau situs Anda untuk menghapus dokumen dan koleksi secara rekursif. Misalnya, Anda dapat menggunakan solusi ini agar pengguna tertentu dapat menghapus seluruh koleksi.

Untuk cara lain menghapus koleksi, lihat Menghapus data.

Solusi: Menghapus data dengan Cloud Function callable

Menghapus seluruh koleksi dari aplikasi seluler dengan resource terbatas bisa jadi sulit diterapkan karena alasan berikut:

  • Tidak ada operasi yang menghapus koleksi secara atomik.
  • Menghapus suatu dokumen tidak otomatis menghapus dokumen dalam subkoleksinya.
  • Jika dokumen Anda memiliki subkoleksi dinamis, mungkin sulit untuk mengetahui data apa yang akan dihapus untuk sebuah jalur tertentu.
  • Menghapus koleksi dengan lebih dari 500 dokumen memerlukan beberapa batch operasi tulis atau ratusan penghapusan satu per satu.
  • Di banyak aplikasi, memberikan izin kepada pengguna akhir untuk menghapus seluruh koleksi bukanlah tindakan yang tepat.

Walau begitu, Anda dapat menulis Cloud Function callable untuk menjalankan penghapusan yang aman dan tepat untuk seluruh koleksi atau hierarki koleksi. Cloud Function di bawah ini menerapkan fungsi callable sehingga dapat dipanggil langsung dari aplikasi seluler atau situs Anda, seperti yang Anda lakukan untuk fungsi lokal.

Untuk men-deploy fungsi tersebut dan mencoba demo, lihat kode contoh.

Cloud Function

Cloud Function di bawah ini akan menghapus koleksi dan semua turunannya.

Anda dapat memanfaatkan perintah firestore:delete di Firebase Command Line Interface (CLI), dan tidak perlu menerapkan logika penghapusan rekursif untuk Cloud Function Anda. Anda dapat mengimpor setiap fungsi Firebase CLI ke aplikasi Node.js menggunakan firebase-tools paket.

Firebase CLI menggunakan Cloud Firestore REST API untuk menemukan semua dokumen di jalur tertentu dan menghapusnya satu per satu. Penerapan ini tidak memerlukan pengetahuan mengenai hierarki data tertentu pada aplikasi, dan bahkan Anda dapat menemukan serta menghapus dokumen turunan yang tidak lagi memiliki induk.

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

Pemanggilan Klien

Untuk memanggil fungsi, dapatkan referensi ke fungsi tersebut dari Firebase SDK dan teruskan parameter yang diperlukan:

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
Catatan: Produk ini tidak tersedia di target watchOS dan App Clip.
    // Snippet not yet written
    
Objective-C
Catatan: Produk ini tidak tersedia di target watchOS dan 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
                    // ...
                }
            });
}

Dengan menggunakan SDK klien untuk fungsi cloud callable, status autentikasi pengguna dan parameter path diteruskan dengan lancar ke fungsi jarak jauh. Ketika fungsi tersebut selesai, klien akan menerima callback yang berisi hasil atau pengecualian. Untuk mempelajari cara memanggil fungsi cloud dari Android, Apple, atau platform lain, baca dokumentasinya.

Keterbatasan

Solusi di atas menunjukkan penghapusan koleksi dari fungsi callable, tetapi Anda perlu memahami sejumlah batasan berikut:

  • Konsistensi - kode di atas menghapus dokumen satu per satu. Jika Anda mengajukan kueri saat operasi penghapusan berlangsung, hasilnya mungkin akan menggambarkan status yang selesai sebagian, dengan hanya beberapa dokumen target yang sudah terhapus. Selain itu, tidak ada jaminan bahwa operasi penghapusan akan berhasil atau gagal secara seragam. Jadi, bersiaplah untuk menangani kasus penghapusan sebagian.
  • Waktu tunggu - fungsi di atas dikonfigurasi untuk dijalankan selama maksimal 540 detik sebelum waktu habis. Kode penghapusan dapat menghapus 4.000 dokumen per detik dalam kondisi terbaik. Jika perlu menghapus lebih dari 2 juta dokumen, pertimbangkan untuk menjalankan operasi tersebut di server Anda sendiri agar tidak mengalami waktu habis. Untuk contoh cara menghapus koleksi dari server Anda sendiri, lihat Menghapus koleksi.