何をするか
Cloud Firestore は、Firebase サービス(あるいは GCP)が提供するサーバーレスな NoSQL データベースです。 Firestore データベースには様々な環境からアクセスできますが、ここでは Web サイトからアクセスすることを想定して、Firebase が提供する JavaScript SDK(クライアントサイド SDK)を使って Firestore データベースを操作してみます。
前提条件として、Firebase プロジェクトの作成は完了し、FirebaseApp
インスタンスの初期化コードは準備できているものとします。
Firestore データベースの作成
クライアントアプリの実装を始める前に、Firebase プロジェクトに Firestore データベースを作成します。
- Firebase コンソール にサインインして、対象のプロジェクトを開く。
- サイドバーから
Firestore Database
を選択し、データベースの作成
をクリックする。- 保護ルールは
本番環境モード
を選んでおけば OK - ロケーションは
asia-northeast1
(東京)を選んでおけば OK
- 保護ルールは
次のように空っぽのデータベースが作成されれば準備 OK です。

テスト用コレクション (books) の作成
Web アプリからのデータ取得を試したいので、まずは Firebase コンソール上で Firestore データベースのテスト用コレクション (books) を作成することにします。
Firestore Database のデータタブから コレクションを開始 を押して、
books
という名前でコレクションを追加します。最初のドキュメント(データ)の情報追加画面になるので、こんな感じでデータを追加します。
- ドキュメントID:
id-1
- フィールド
title
: (string)Title-1
- フィールド
author
: (string)Author-1
- フィールド
price
: (number)1000
- ドキュメントID:
無事に books
コレクションを作成できたら、ドキュメントを追加 を押して、適当に 3 つくらいデータを登録しておきます。

例えば、こんな感じでドキュメントを追加しておきます。
ドキュメントID | title | author | price |
---|---|---|---|
id-1 | Title-1 | Author-1 | 1000 |
id-2 | Title-2 | Author-2 | 2000 |
id-3 | Title-3 | Author-3 | 3000 |
セキュリティルールの設定
クライアントアプリ(Web アプリやモバイルアプリ)からの Firestore データベースへのアクセス制御は、セキュリティルール で設定します。 例えば、「サインイン済みのユーザーにのみコレクションの読み書き許可する」といった設定が可能です。
ここではとりあえず、books
コレクションは誰でも読み取り可能で、書き込みは不可というルールに設定してみます。
Firestore Database の ルール タブを選択すると、セキュリティルールを編集できます。
デフォルトでは、おそらく次のようになっています。
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if false;
}
}
}
これは、「いかなるドキュメントに対しても読み書きを許可しない」という設定なので、次のように編集して保存します。
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /books/{document=**} {
allow read: if true;
allow write: if false;
}
}
}
上記のルール設定は、次のような意味を持っています。
- books コレクション以下の全てのドキュメントが対象 (
match /books/{document=**}
) - 読み込みは許可 (
allow read: if true;
) - 書き込みは不可 (
allow write: if false;
)
これで、Firestore 側の books
コレクションの準備は完了です。
クライアントコードの作成
Firestore の準備ができたので、Web アプリ (Next.js/React) のコードからデータ取得してみます。
カスタムフック (useBooks
) を作って、Firestore の books
コレクション内のすべてのドキュメントを取得します。
firebase パッケージのインストールや、FirebaseApp
インスタンスの初期化用コード init.ts
の作成は終わっているものとします(参考: FirebaseApp の初期化)。
Firestore アクセス部分
まずは、Firestore から books
コレクション内のドキュメントを取得してくるコードを作成します。
Book
データ型もここで定義しておきます。
import { collection, getDocs, getFirestore } from 'firebase/firestore'
// import './init' // Initialize FirebaseApp
export type Book = {
id: string
title: string
author: string
price: number
}
export async function getBooks(): Promise<Book[]> {
const books = new Array<Book>()
const db = getFirestore()
const booksSnapshot = await getDocs(collection(db, '/books'))
booksSnapshot.forEach((doc) => {
const book = doc.data() as Book
books.push({ ...book, id: doc.id })
})
return books
}
データ取得用のカスタムフック
React コンポーネントからデータ取得したいので、上記で作ったコードを useBooks
カスタムフックの形にラップします。
ここでは、直接 getBooks()
を呼び出していますが、最終的には useSWR フックを使ってデータフェッチ することをお勧めします。
import { useEffect, useState } from 'react'
import { Book, getBooks } from '../utils/firebase/books'
export type UseBooksOutput = {
isLoading: boolean
books: Book[]
}
const DEFAULT_OUTPUT: UseBooksOutput = {
isLoading: true,
books: [],
}
export function useBooks(): UseBooksOutput {
const [output, setOutput] = useState(DEFAULT_OUTPUT)
useEffect(() => {
void (async () => {
const books = await getBooks()
setOutput({ isLoading: false, books })
})()
}, [])
return output
}
React コンポーネント
あとは、適当なコンポーネントから、useBooks
フックを使って取得した情報を表示すれば OK です。
import { FC } from 'react'
import { useBooks } from '../hooks/useBooks'
export const BookTable: FC = () => {
const { isLoading, books } = useBooks()
if (isLoading) return <p>Loading...</p>
return (
<ul>
{books.map((book) => (
<li key={book.id}>
{book.title} / {book.author} / {book.price}
</li>
))}
</ul>
)
}
上記のコンポーネントをレンダリングして、次のように表示されれば成功です。
- Title-1 / Author-1 / 1000
- Title-2 / Author-2 / 2000
- Title-3 / Author-3 / 3000
おまけ: Firestore にドキュメントを追加するコード
上記の例では、Firestore からのドキュメントの読み込みを試しましたが、ドキュメントの追加も似たようなコードで実現できます。
下記の addBook
関数は、渡された Book
オブジェクトの情報を Firestore の books
コレクションに追加します。
import { collection, doc, getDocs, getFirestore, setDoc } from 'firebase/firestore'
// ...
// export async function getBooks(): Promise<Book[]> { ... }
// ...
export async function addBook(book: Book): Promise<void> {
const db = getFirestore()
const docRef = doc(db, 'books', book.id)
await setDoc(docRef,
{ title: book.title, author: book.author, price: book.price },
{ merge: true /* ドキュメントが存在する場合はフィールドを追記 */ }
)
}
実際にこのコードを呼び出すときは、Firestore のセキュリティルールで write 許可しておく必要があります。
次のステップ
- Firebase Auth で admin ユーザーのみ Firestore に書き込みできるようにする
- Firestore ドキュメントを TypeScript のユーザー定義型オブジェクトに変換する (withConverter)
関連記事
- Next.js で Firebase: Authentication 機能でユーザー認証できるようにする
- Next.js で Firebase: プロジェクトの作成と接続準備
- Next.js で useState とローカルストレージ (localStorage) を連動させる
- Next.js から AWS DynamoDB にアクセスする
- Next.js で開発環境で実行しているときに Web サイト上に dev 表示する (TargetEnvIndicator)
- Next.js で src からの相対パスで import できるようにする (tsconfig.json)
- Next.js のページコンポーネントが Client と Server どちらで実行されているか調べる (isServer, isClient, NoSsr)