Firebase Summit のすべての発表内容に目を通し、Firebase を活用してアプリ開発を加速し、自信を持ってアプリを実行できる方法をご確認ください。 詳細

呼び出し可能なクラウド関数を使用してデータを削除する

コレクションでコンテンツを整理 必要に応じて、コンテンツの保存と分類を行います。

このページでは、呼び出し可能な Cloud Function を使用してデータを削除する方法について説明します。この関数をデプロイすると、モバイル アプリまたは Web サイトから直接呼び出して、ドキュメントとコレクションを再帰的に削除できます。たとえば、このソリューションを使用して、選択したユーザーにコレクション全体を削除する権限を与えることができます。

コレクションを削除するその他の方法については、「データを削除する」を参照してください。

解決策: 呼び出し可能な Cloud Function を使用してデータを削除する

リソースが限られているモバイル アプリからコレクション全体を削除することは、次の理由で実装が難しい場合があります。

  • コレクションをアトミックに削除する操作はありません。
  • ドキュメントを削除しても、そのサブコレクション内のドキュメントは削除されません。
  • ドキュメントに動的なサブコレクションがある場合、特定のパスでどのデータを削除すればよいかを判断するのが難しい場合があります。
  • 500 を超えるドキュメントのコレクションを削除するには、複数回の一括書き込み操作または数百回の単一削除が必要です。
  • 多くのアプリでは、コレクション全体を削除するアクセス許可をエンド ユーザーに与えることは適切ではありません。

幸いなことに、呼び出し可能な Cloud Functionを作成して、コレクション全体またはコレクション ツリーの安全で効率的な削除を実行できます。以下の Cloud Function は、呼び出し可能な関数を実装しています。これは、ローカル関数の場合と同様に、モバイル アプリまたは Web サイトから直接呼び出すことができることを意味します。

関数をデプロイしてデモを試すには、サンプル コードを参照してください。

クラウド機能

以下の Cloud Function は、コレクションとそのすべての子孫を削除します。

Cloud Function に独自の再帰的な削除ロジックを実装する代わりに、Firebase コマンドライン インターフェース (CLI) でfirestore:deleteコマンドを利用できます。 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);
        });
}
迅速
注:この製品は、watchOS および App Clip ターゲットでは使用できません。
    // Snippet not yet written
    
Objective-C
注:この製品は、watchOS および App Clip ターゲットでは使用できません。
    // Snippet not yet written
    

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

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
                // ...
            }
}

呼び出し可能なクラウド関数のクライアント SDK を使用することで、ユーザーの認証状態とpathパラメーターがリモート関数にシームレスに渡されます。関数が完了すると、クライアントは結果または例外を含むコールバックを受け取ります。 Android、Apple、またはその他のプラットフォームからクラウド関数を呼び出す方法については、ドキュメントを参照してください。

制限事項

上記のソリューションは、呼び出し可能な関数からコレクションを削除する方法を示していますが、次の制限に注意する必要があります。

  • 一貫性- 上記のコードはドキュメントを一度に 1 つずつ削除します。進行中の削除操作中にクエリを実行すると、対象となる一部のドキュメントのみが削除された、部分的に完了した状態が結果に反映される場合があります。また、削除操作が一様に成功または失敗するという保証もありません。そのため、部分削除のケースに対処する準備をしてください。
  • タイムアウト- 上記の関数は、タイムアウトするまで最大 540 秒間実行するように構成されています。削除コードは、最高の場合で 1 秒あたり 4000 ドキュメントを削除できます。 2,000,000 を超えるドキュメントを削除する必要がある場合は、タイムアウトしないように、独自のサーバーで操作を実行することを検討する必要があります。自分のサーバーからコレクションを削除する方法の例については、コレクションの削除を参照してください。