🐙

[Firebase] Cloud FunctionsでFirestoreのドキュメントとサブコレクションをまとめて削除する方法

2021/10/31に公開

はじめに

Firestoreはドキュメントを削除してもドキュメント配下にあるサブコレクションは残ってしまいます。
https://firebase.google.com/docs/firestore/manage-data/delete-data?hl=ja#delete_documents

ドキュメントを削除するときにサブコレクションのドキュメントも一つずつ削除していけば良いですが、サブコレクションが増えてきたらかなり面倒。

ドキュメント削除したときには以下にあるサブコレクションもまとめて削除する方法を調べていたところ、Firebase CLIのfirestore:deleteコマンドを利用することで一括で削除できると書いてありました。firebase-toolsを使うことでFirebase CLIの関数を使えます。
公式ではこの方法を推奨しているようです。
https://firebase.google.com/docs/firestore/solutions/delete-collections?hl=ja#cloud_function

なので、Cloud Functionsのドキュメント削除(onDelete)をトリガーにして、ドキュメント配下のサブコレクションも一括で削除する方法を紹介します。
(Cloud FunctionsはTypescriptで書いています)

firebase-toolsをインストール

まずはfirebase-toolsをfunctionsディレクトリにインストールしましょう!

$ npm install firebase-tools

↓のような感じでfunctions/package.jsonに追加されていると思います。

{
  "name": "functions",
  ...
  "dependencies": {
    "firebase-admin": "^8.10.0",
    "firebase-functions": "^3.6.1",
+   "firebase-tools": "^9.20.0"
  },
  ...
}

環境変数にトークンを設定

firebaseにログイン認証してトークンを取得します。

$ firebase login:ci

Visit this URL on this device to log in:
[ここに表示されるURLに飛んでログイン]

Waiting for authentication...

✔  Success! Use this token to login on a CI server:

# ここにトークンが表示されるのでコピーしておいてください
**********

Example: firebase deploy --token "$FIREBASE_TOKEN"

次にコピーしたトークンを環境変数に設定します。

$ firebase functions:config:set fb.token="さっきコピーしたトークン"
✔  Functions config updated.

Please deploy your functions for the change to take effect by running firebase deploy --only functions

Cloud Functionに処理を追加

usersコレクション内のドキュメント削除をトリガーにドキュメント配下のサブコレクションを全て削除する処理を追加していきます。

使用する環境変数の
process.env.GCLOUD_PROJECTはプロジェクト作成時に自動で設定されているものなので、そのまま使えます。
functions.config().fb.tokenはさっき設定したトークンが入っています。

index.ts
import * as functions from 'firebase-functions'
import * as admin from 'firebase-admin'

// firebase_toolsをインポート
const firebase_tools = require('firebase-tools')

admin.initializeApp(functions.config().firebase)

export const onDelete = functions
  .region('asia-northeast1')
  .firestore
  .document('users/{uid}')
  .onDelete(async (snapshot, context) => {
    // 環境変数の確認用
    console.log(process.env.GCLOUD_PROJECT)
    console.log(functions.config().fb.token)

    try {
      // 削除されたドキュメントのパスを取得
      const path = snapshot.ref.path

      await firebase_tools.firestore
        .delete(path, {
          project: process.env.GCLOUD_PROJECT,
          recursive: true,
          yes: true,
          token: functions.config().fb.token
        })
    } catch (error) {
      console.log(error)
      throw error
    }
  })

これでユーザードキュメント削除時にサブコレクションを一括で削除されるようになりました。

参考

https://firebase.google.com/docs/firestore/manage-data/delete-data?hl=ja#delete_documents
https://firebase.google.com/docs/firestore/solutions/delete-collections?hl=ja#cloud_function

Discussion