TypeScriptでFirestoreからデータを取り出す(FirebaseSDKv9)

前置き

「実践編:React NativeとFirebaseで作るiOS/Androidアプリ:お店レビューアプリ開発編」 www.udemy.com にトライしております。(Expoおもしろい〜)

Firebaseのバージョンが前のもので解説されており、せっかくなのでV9で書きたいなと思ったのですが思いのほか書き方が過去バージョンとだいぶ異なっており混乱したので整理しました。

※講義内で言及されている通りV9での動作確認はまだのでこの先V9の書き方だと詰まるかもしれないです。
※講義10までしか見ていない段階なので、この先も視聴して内容を適宜修正するかもしれないです。

2022/3/12追記
今のところはExpoでFirebaseSDKV9を動かすのは無理かもしれないです。
stackoverflow.com
github.com
でも修正プルリクが動いているようなのでもうすぐ動くようになりそうです!楽しみ&感謝

環境

node-version:16.13.2
typescript:4.6.2
firebase:9.6.8

Firestoreの状態

f:id:Tiratom:20220310204733p:plain
Firestoreのデータの状態

ドキュメント1つ分のデータ取得の流れ

では、FirestoreからID=1の name="ビストロ品川", place="品川" のデータを取得する方法について整理します。

手順概要

  1. ドキュメントのデータ用の型を用意する
  2. コレクション(ドキュメントを束ねる単位。ここでは写真の一番左列のshops)への参照を取得する
  3. 2の参照をもとにドキュメント(ここでは写真の真ん中列の1)への参照を取得する
  4. 3の参照をもとにドキュメント(ここでは写真の右列の内容が該当)のデータを取得する
  5. 4で取得したデータから必要なものを取り出す(ここでは写真の右列でいうnameやplaceなど)

手順詳細

1. ドキュメントのデータ用の型を用意する

最終的に取り出すデータの内容に合わせて型を用意します。取り出したデータを扱っていく上で型があると安心便利なので用意します。

export type Shop = {
  name: string,
  place: string
}

2. コレクション(ドキュメントを束ねる単位)への参照を取得する

先ほどのスクリーンショットでいうと左列の中のshopsへの参照を取得します。ここで先ほど用意した型でアサーションすることで、最終的なデータ取得時にShop型で扱えます。

const shopsColRef = collection(
  firestore,
 "shops"
) as CollectionReference<Shop>;   

3. 2の参照をもとにドキュメントへの参照を取得する

ここではIDが1であるドキュメントへの参照を取得しています。

const shopsDocRefId1 = doc(shopsColRef, "1");

4. 3の参照をもとにドキュメントのデータを取得する

非同期処理です。

const shopsDocId1 = await getDoc(shopsDocRefId1);

5. 4で取得したデータから必要なものを取り出す

data()で一般的に想像するいわゆるデータを取得できます。(他にはid()でIDを取得したりもできます)

const shopsDataId1 = shopsDocId1.data();
console.log(shopsDataId1);

上記の出力は、Object { place: "品川", name: "ビストロしながわ" } といった感じとなります。

コレクション1つ分(複数ドキュメント)のデータ取得の流れ

次に、Firestoreからshopsのコレクションに含まれるすべてのドキュメントのデータを取得する方法について整理します。

手順概要

  1. ドキュメントのデータ用の型を用意する
  2. コレクション(ここでは写真の左の列のShops)への参照を取得する
  3. 2の参照をもとにコレクションのデータ(ここでは真ん中の列で言う1, 2, 3のドキュメント)を取得する
  4. 3で取得したデータから必要なものを取り出す

手順詳細

1. ドキュメントのデータ用の型を用意する

「ドキュメント1つ分のデータ取得方法」の1. と同じ内容ですが再掲。

export type Shop = {
  name: string,
  place: string
}

2. コレクション(ドキュメントを束ねる単位)への参照を取得する

先ほどのスクリーンショットで言うshopsの項目への参照を取得します。

const shopsColRef = collection(
  firestore,
 "shops"
) as CollectionReference<Shop>;

3. 2の参照をもとにコレクションのデータを取得する(複数ドキュメントを持つ)

const shopsDocs = await getDocs(shopsColRef);

4. 3で取得したデータから必要なものを取り出す

const shopsAllData = shopsDocs.docs.map((doc) => doc.data());
console.log(shopsAllData);

出力内容は、以下の感じ(抜粋)になります。

Array(3) [ {…}, {…}, {…} ]
0: Object { place: "品川", name: "ビストロしながわ" }
1: Object { name: "タマチピザ", place: "田町" }
2: Object { place: "有楽町", name: "Yurakucho Cafe" }
length: 3

shopsColRef作成時にShopsで型を指定しているおかげで、shopsAllDataを扱う際の .name呼び出し時にタイプミスや存在しないプロパティアクセスをしてしまう心配がありません。

console.log(shopsAllData[0].name);

出力内容は、ビストロしながわ となります。

ソースをまとめたもの

import { getFirestore, collection } from "firebase/firestore";
import { initializeApp } from "firebase/app";
import { CollectionReference, doc, getDoc, getDocs } from "@firebase/firestore";

const firebaseApp = initializeApp({ /* config */ });

const firestore = getFirestore(firebaseApp);

type Shop = {
  name: string,
  place: string
}

const shopsColRef = collection(
  firestore,
  "shops"
) as CollectionReference<Shop>;

export const getDocumentByIdExample = async(id: string) => {
  const shopsDocRefId1 = doc(shopsColRef, id);
  const shopsDocId1 = await getDoc(shopsDocRefId1);
  const shopsDataId1 = shopsDocId1.data();
  console.log(`id=${id}のデータ`) 
  console.log(shopsDataId1);  // → Object { place: "品川", name: "ビストロしながわ" }
}

export const getDocumentsExample = async () => {
  const shopsDocs = await getDocs(shopsColRef);
  const shopsAllData = shopsDocs.docs.map((doc) => doc.data());
  console.log("Shopsコレクションの全データ")
  console.log(shopsAllData)  // → Array(3) [ {…}, {…}, {…} ]
  console.log("Shopsコレクションの1番目の項目のnameの値")
  console.log(shopsAllData[0].name); // → ビストロしながわ
};

参考

javascript.plainenglish.io

こちらのサイトではコレクションへの参照取得時用メソッドを用意しているなど、実プロジェクトで使う際に良いお手本になりそうです。

qiita.com

こちらの説明のおかげでFirestoreの処理内容が把握できました。

qiita.com

冒頭で言及したUdemyのExpoの講座の講師の記事です