使用可呼叫的 Cloud 函式刪除資料

本頁面說明如何使用可呼叫的 Cloud 函式刪除資料。部署這個函式後,即可直接從行動應用程式或網站呼叫這個函式,以遞迴方式刪除文件和集合。例如,您可以使用這個解決方案,讓特定使用者刪除整個集合。

如要瞭解其他刪除集合的方式,請參閱「刪除資料」。

解決方案:使用可呼叫的 Cloud 函式刪除資料

難以從資源有限的行動應用程式中刪除整個集合,原因如下:

  • 沒有任何作業會以不可分割的形式刪除集合。
  • 刪除文件並不會刪除其子集合中的文件。
  • 如果您的文件含有動態子集合,您可能很難知道該從特定路徑刪除哪些資料。
  • 如要刪除內含 500 個文件的集合,就必須執行多次批次寫入作業,甚至是數百個單刪除作業。
  • 在許多應用程式中,請勿讓使用者取得刪除整個集合的權限並不適當。

幸好,您可以編寫可呼叫的 Cloud 函式,以安全且執行整個集合或集合樹狀結構刪除作業。下列 Cloud 函式會實作可呼叫函式,這表示您可以像使用本機函式一樣,直接從行動應用程式或網站呼叫該函式。

如要部署函式並試用,請參閱程式碼範例

Cloud 函式

下方的 Cloud 函式會刪除集合及其所有子系。

您可以在 Firebase 指令列介面 (CLI) 中使用 firestore:delete 指令,而不必為 Cloud 函式實作自己的遞迴刪除邏輯。您可以使用 firebase-tools 套件,將 Firebase CLI 的任何函式匯入 Node.js 應用程式。

Firebase CLI 會使用 Cloud Firestore REST API 找出指定路徑下的所有文件,並個別刪除文件。這項實作無需瞭解應用程式的特定資料階層,甚至會尋找並刪除已沒有父項的「孤立」文件。

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

用戶端叫用

如要呼叫函式,請從 Firebase SDK 取得函式參照,並傳遞必要參數:

網站
/**
 * 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
注意:這項產品不適用於 watchOS 和 App Clip 目標。
    // Snippet not yet written
    
Objective-C
注意:這項產品不適用於 watchOS 和 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
                    // ...
                }
            });
}

透過使用用戶端 SDK 處理可呼叫的 Cloud 函式,使用者的驗證狀態和 path 參數會順暢地傳遞至遠端函式。函式執行完成後,用戶端會收到結果或例外狀況的回呼。如要瞭解如何從 Android、Apple 或其他平台呼叫 Cloud 函式,請參閱說明文件

限制

上述解決方案示範如何從可呼叫函式刪除集合,但您應瞭解下列限制:

  • 一致性 - 上述程式碼會一次刪除一個文件。如果在有進行中的刪除作業時執行查詢,結果可能會反映部分完整狀態,其中僅刪除部分指定文件。我們也無法保證刪除作業會統一執行成功或失敗,因此請準備好處理部分刪除的情況。
  • 逾時 - 上述函式已設定為最長執行 540 秒,之後就會逾時。在最佳情況下,刪除代碼每秒可以刪除 4000 份文件。如需刪除超過 2,000,000 份文件,請考慮在自己的伺服器上執行作業,以免逾時。如需如何從自己的伺服器刪除集合的範例,請參閱「刪除集合」。