見出し画像

【Python3+Firestore】PythonアプリからFirestoreにアクセスする2024

以前の記事

を参考に新しいアプリを作ろうとしたら動かなかったので情報を更新していきますよっと。

今回は、既にFirestoreデータベースは作ってある前提でさくっとデータを取得しに行きます。とりあえずテスト用にデータベースを作ってみたい場合はGUIからやればすぐできる。

公式ドキュメントより始めよ

はい

言われた通りにやってみる

管理用パッケージをインストール

$ pip install --upgrade firebase-admin

推奨パッケージが変わっていますね。使い方も変わっているのだろう…

ローカル開発時用の認証情報を取得

$ gcloud auth application-default login

で、GCPにログインしておきます。(※ただの auth login だとダメ。「application-default」必須)
参考⇒https://devblog.pirika.org/entry/2022/01/17/110000

Firebaseアプリを初期化

import firebase_admin
from firebase_admin import firestore

app = firebase_admin.initialize_app(options={`projectId`:`PROJECT-ID`})
db = firestore.client()

ローカルで開発する場合は先ほど認証情報を取得したのでそれでOK、作ったアプリをGCP上で動かすなら認証情報は自動で入る。自分で用意したサーバーで動かしたい場合は認証キーが必要。詳細は公式ドキュメント参照。

上記のapplication-defaultを使って認証している場合、プロジェクトIDを明示的に指定できないので、複数のプロジェクト横断で開発している場合はここでoptionsを使って指定する。

データを読み取る

公式ドキュメントはここ

単一のドキュメントを取得する

# アプリの初期化をしてから

# 参照を取得する(DBにアクセス可能なパスを生成するイメージ・DBアクセスはしない)
doc_ref = db.collection("コレクション名").document("ドキュメントID")

# ここでDBにアクセスしてスナップショットを取得する
doc = doc_ref.get()

if doc.exists:
    print(f"Document data: {doc.to_dict()}")
else:
    print("No such document!")

ドキュメントへの参照を一度取得してから、get()で中身を取得する。
ドキュメントの中身はto_dict()で辞書にできる。

getを使って初めて、オンラインの最新のスナップショットを取得する。

コレクションを取得して、その配下のドキュメントを取得する

「ユーザー」コレクションの中に登録ユーザーの情報が入ったドキュメントが「1」「2」「3」…と増えていくような作りをしている場合、ユーザーの一覧を取得したいと思ったら、「ユーザー」コレクションを引っ張ってきてそのIDの一覧を取りたいと思うことでしょう。

それ。

# コレクション配下にあるドキュメントのをすべて取得する
docs = db.collection("コレクション名").stream()

# 取得したドキュメントを解体して、辞書形式に整形する
ドキュメント一覧 = {}
for doc in docs:
    # ドキュメントIDを取得
    ドキュメントID = doc.id

    # ドキュメントの中身を辞書形式で取得
    ドキュメント = doc.to_dict()

    # ドキュメント一覧に登録
    ドキュメント一覧.setdefault(ドキュメントID, ドキュメント)

どっこいしょっと。

ただし、「配下にコレクションしか存在しないドキュメント」は取得できない

うそだろ…という仕様なんですけど、「あるコレクションAの配下に複数のドキュメントB,C,Dがあり、そのドキュメント群はそれぞれ配下にコレクションEのみを持つ(そのドキュメントにフィールドがない)」場合、コレクションAのstreamを取得しても、B,C,DのIDは取得されません。なんだって。

なので、コレクションAに含まれるドキュメントIDのリストを取得して順繰りにアクセスして…みたいな実装はできません

できません。

……そっかー。

※ただ、ドキュメントのリストを取得して順繰りにアクセスするような実装をすると、Firestoreの仕様上めちゃくちゃお金がかかるので、こんな実装が必要になるような設計はそもそもしない方がいいです。

もうDB作っちゃったけどどうしても上記のようなアクセスしたいよーーという場合は、お金がものすごくかかることを覚悟の上で、
①:コレクションAに含まれるドキュメントIDのリストを何とかして別に持てるようにして、そっちの情報を参照してfor処理できるようにする
②:コレクションAに含まれるドキュメントBDCすべてに手作業で適当なフィールドを挿入する(+今後作られるドキュメントには適当なフィールドが挿入されるようにする)
という方法でなんとかできます。
この時、①にしても②にしても、GUIでドキュメント一覧を表示するとドキュメントIDだけわーっとコピペできるので、取り合えずそれで結構救われます。

とりあえずこれでFirebaseからごそっとデータを取ってくる部分は作れそうです。
空ドキュメントにコレクションを持たせるような設計をしたくなったら、おとなしくRDBを選択した方がいいのかもしれません。学び。

この記事が気に入ったらサポートをしてみませんか?