📑

「FirebaseAuthユーザが削除⇨対象のFirestoreデータも削除する」コードをCloud Run Functionsで実行させる

2024/09/13に公開

はじめに

  • ユーザの認証や管理をFirebase Authenticationで利用している場合,ユーザのサービス退会・解約(削除)と連動して,Firestoreデータベースを削除したいケースがあると思います.それをCloud Run FunctionsのFirebase Authentication Triggersを利用して,行いたいと思います.

注意点

  • Firestoreの特性上,ドキュメントを削除しても、そのドキュメントのサブコレクションは削除されません。
  • また,コレクションおよびサブコレクションを削除する場合,小さいバッチに分けてドキュメントを削除することが推奨されています.
  • さらに,webフロントエンドやモバイルアプリから,コレクションおよびサブコレクション等の削除操作は,推奨されていません.

開発環境・前提

  • python3.12
  • Cloud Run Functions(旧Cloud Functions):第一世代
    ※Firebase Authentication Triggersあ,第一世代のみに対応しているため.
  • gcloudコマンドが使用できる状態であること

Firestoreの構成

  • 私のfirestoreでは,下記のような構成になっています.
users(Collection)
    ⇨ <uid>(Document.Firebase Authユーザのuidを利用)
        ⇨ recipes(Collection)
            ⇨ <id> (Document. idは,登録時に自動生成したもの)
                ⇨ フィールド値1
                ⇨ フィールド値2
                ⇨ フィールド値3

実装

requirements.txt

  • Firebase Admin SDK を Python アプリに追加します。
requirements.txt
firebase_admin==6.5.0

main.py

  • Google Cloudで,Cloud Firestoreのインスタンスを初期化する場合,
app = firebase_admin.initialize_app()
db = firestore.client()

とすればいいです.

  • 下記が,コード例(main.py)です.
main.py
import firebase_admin
from firebase_admin import credentials
from firebase_admin import firestore

# # local environment
# cred = credentials.Certificate("service-account.json")

# app = firebase_admin.initialize_app(cred)
# db = firestore.client()

# google cloud environment
app = firebase_admin.initialize_app()
db = firestore.client()

def delete_firestore_by_user_deletion(data, context):
    # dataから削除されたユーザの情報を取得.
    uid = data["uid"]
    print(f"Function triggered by deletion of user: {uid}")
    
    user_ref = db.collection("users").document(uid)
    print("making refrence data to user_ref")
    recipes_collection_ref = user_ref.collection("recipes")
    print("making refrence data to recipes_collection_ref")
    print(f"In delete_firestore_by_user_deletion, user_ref: {user_ref}, recipes_collection_ref: {recipes_collection_ref}")

    # delete recipes collection
    try:
        delete_recipes_collection(recipes_collection_ref, 100)
        print(f"Recipes collection deleted.")
    except firebase_admin.exceptions.FirebaseError as e:
        print(f"Error deleting recipes collection: {e}")
    
    # delete user document
    try:
        delete_user(user_ref)
        print(f"User document deleted.")
    except firebase_admin.exceptions.FirebaseError as e:
        print(f"Error deleting user document: {e}")


def delete_recipes_collection(coll_ref, batch_size):
    docs = coll_ref.list_documents(page_size=batch_size)
    deleted = 0

    for doc in docs:
        print(f"Deleting doc {doc.id} => {doc.get().to_dict()}")
        doc.delete()
        deleted = deleted + 1

    if deleted >= batch_size:
        return delete_recipes_collection(coll_ref, batch_size)
    

def delete_user(user_ref):
    user_ref.delete()

デブロイする

deploy.sh
gcloud functions deploy deleteFirestoreByUserDeletion \ # ファンクション名.適当に
    --no-gen2 \ #
    --entry-point delete_firestore_by_user_deletion \ # 対象のpython関数名
    --trigger-event providers/firebase.auth/eventTypes/user.delete \
    --region asia-northeast1 \ # 第一世代をサポートしているリージョンを選んでください.
    --source .\
    --runtime python312

その他:Firebase Admin SDKの利用に関して

  • google cloud以外の環境(ローカル等)で動作検証をしたい場合,サービスアカウントの取得が,必要になります.
  • その際,Cloud Firestoreのインスタンスを初期化するコードは,以下の通りです.
# local environment

# サービスアカウントjsonファイルを読み込む
cred = credentials.Certificate("service-account.json")

app = firebase_admin.initialize_app(cred)
db = firestore.client()

参考資料

  • Cloud Run Functions: Firebase Authentication Triggers

https://cloud.google.com/functions/1stgendocs/calling/firebase-auth

  • Firebaseドキュメント > Firestore:Cloud Firestore を使ってみる

https://firebase.google.com/docs/firestore/quickstart?hl=ja

  • Firebaseドキュメント > Firestore:Cloud Firestore からデータを削除する

https://firebase.google.com/docs/firestore/manage-data/delete-data?hl=ja

Discussion