Firebase Firestoreは、モバイルおよびウェブアプリケーション向けに設計された、GoogleによるクラウドNoSQLリアルタイムデータベースです。クライアント間の自動同期により、コレクションとドキュメントでデータを保存します。公式ドキュメント Firebase, 2025 によると、Firestoreは強整合性を備えたマルチリージョンデプロイメントをサポートし、サーバー管理を必要としない自動スケーリングを提供します。このデータベースはFirebase AuthenticationおよびCloud Functionsと統合し、独自のサーバーインフラストラクチャなしで完全なバックエンドを構築できます。
重要ポイント
Firebase Firestoreは、Googleが2019年にFirebase Realtime Databaseの進化形としてリリースした、柔軟でスケーラブルなNoSQLデータベースです。ドキュメントのコレクションにデータを保存し、各ドキュメントにはキーと値のペアのセットが含まれます。従来のリレーショナルデータベースとは異なり、Firestoreは事前定義されたスキーマを必要とせず、データ構造は書き込まれるドキュメントに基づいて動的に形成されます。
Firestoreと従来のクラウドデータベースの主な違いは、組み込みのリアルタイム同期です。サーバー上のデータが変更されると、接続されているすべてのクライアントが永続的なWebSocket接続を介して更新を受け取ります。これにより、手動のサーバーポーリングが不要になり、チャット、アクティビティフィード、共同エディター、監視システムなどのライブ更新を備えたアプリケーションを構築できます。
このデータベースは、Android、iOS、Web(JavaScript)、Admin SDKを介したサーバー側言語など、すべての主要プラットフォームで利用できます。FirestoreはSwift、Kotlin、JavaScript、Python、Go、Java、Node.js用のSDKを提供しています。Googleによると、FirestoreはFirebaseエコシステム全体で1日あたり1,000億件以上のリクエストを処理しており、本番アプリケーションの基盤としての信頼性を裏付けています。
Firestoreでは、データは階層構造で整理されます。コレクションはドキュメントのコンテナであり、SQLのテーブルに似ていますが、固定スキーマはありません。ドキュメントは、文字列、数値、ブール値、配列、ネストされたオブジェクト、地理ポイントなど、さまざまなタイプのフィールドを含むレコードです。ドキュメントはサブコレクションを含むことができ、任意の深さのネストされたデータ構造を構築できます。
val db = FirebaseFirestore.getInstance()
val user = hashMapOf(
"name" to "Anna Petrova",
"email" to "anna@example.com",
"age" to 28,
"isActive" to true
)
db.collection("users")
.add(user)
.addOnSuccessListener { docRef ->
Log.d("TAG", "ドキュメントがIDで追加されました:${docRef.id}")
}
コレクション内の各ドキュメントには一意の識別子があり、自動生成または手動設定が可能です。Firestoreはすべてのドキュメントフィールドを自動的にインデックス化し、手動インデックス設定なしで、フィルタリング、並べ替え、結果制限を伴う複雑なクエリを可能にします。
FirestoreとFirebase Realtime Databaseは、Googleによる2つのクラウドリアルタイムデータベースです。どちらもリアルタイム同期を提供しますが、データモデル、スケーリング、価格設定において根本的な違いがあります。特定のプロジェクトに適したデータベースを選択する際には、これらの違いを理解することが重要です。
| 特性 | Firestore | Realtime Database |
|---|---|---|
| データモデル | コレクションとドキュメント | 単一のJSONツリー |
| 整合性 | 強整合性 | 結果整合性 |
| クエリ | フィルタリングと並べ替えによる複合クエリ | 1つのパラメータのみによるフィルタリング |
| スケーリング | 自動、マルチリージョン | 単一リージョン、最大200k接続 |
| 価格設定 | 読み取り/書き込み/削除操作ごと | 転送データ量に基づく |
主なアーキテクチャ上の違いはデータモデルです。Realtime Databaseはすべてを1つの大きなJSONツリーに保存するため、深いネストを持つクエリが複雑になります。Firestoreはコレクションとドキュメントを使用し、複数の条件による複雑なクエリを可能にします。さらに、Firestoreは強力なデータ整合性を提供し、書き込み成功後は後続のすべての読み取りが最新データを返すことを保証します。
Firestoreは、マルチリージョンアーキテクチャにより、数百万の同時接続まで自動的にスケーリングします。Realtime Databaseは単一リージョンに制限され、最大200,000の同時接続です。グローバルなユーザーを対象とするプロジェクトにはFirestoreが推奨されます。データは複数のGoogleデータセンター間で自動的にレプリケートされるためです。
Firestoreのデータ構造により、サブコレクションを含む複雑な階層モデルを構築できます。たとえば、ユーザーが「注文」サブコレクションを持ち、各注文が「アイテム」サブコレクションを持つことができます。Realtime Databaseでは、このような深いネストはクエリ中にパフォーマンス問題を引き起こします。ルートから必要なノードまでのパス全体が読み込まれるためです。
Firestoreは、リアルタイムデータ同期のためにクライアントとサーバー間で永続的なWebSocket接続を使用します。アプリケーションがスナップショットリスナーを介してドキュメントやコレクションの変更を購読すると、SDKは通信チャネルを確立し、データが変更されるたびにサーバーが更新を送信します。クライアントは毎回コレクション全体の完全なスナップショットではなく、変更されたドキュメントのみを受信します。
同期メカニズムはイベントストリームに基づいています:added(ドキュメント出現)、modified(ドキュメント変更)、removed(ドキュメント削除)。開発者は各イベントを個別に処理し、対応するUI要素のみを更新できます。これにより、数千のドキュメントがあっても高いパフォーマンスが保証され、変更されたコンポーネントのみが再レンダリングされます。
Firestoreの主な利点の1つは、組み込みのオフラインモードサポートです。SDKは自動的に読み取ったすべてのデータをデバイスにキャッシュし、ネットワークがない場合でも動作を継続します。アプリケーションがオフラインモードでデータを書き込むと、ローカルキューに配置され、接続が復元されたときにサーバーに送信されます。競合解決にはlast-write-wins戦略が使用されます。
val docRef = db.collection("cities").document("SF")
docRef.addSnapshotListener { snapshot, error ->
if (error != null) {
Log.w("TAG", "リスニングエラー", error)
return@addSnapshotListener
}
if (snapshot != null && snapshot.exists()) {
Log.d("TAG", "現在のデータ:${snapshot.data}")
}
}
キャッシュサイズはFirestoreSettingsで設定できます。デフォルト値は100 MBですが、データ読み取りが多いアプリケーションでは増やすことができます。アプリケーションの再起動後も持続する永続ディスクキャッシュモードも利用できます。オフラインモードの可用性を管理するには、enableNetworkメソッドとdisableNetworkメソッドを使用し、ネットワーク通信を一時的に無効にすることができます。
Firestore Security Rulesは、サーバーレベルでデータアクセスを制御するための宣言型マークアップ言語です。ルールは誰がどのような条件でドキュメントを読み書きできるかを定義します。ルールはクエリ実行前に機能し、認可のために別のサーバーロジックを必要としません。ルールはデータの読み取りまたは書き込みの前にFirebase側でチェックされます。
アクセスルールは許可(allow)の原則に基づいて構築されています。デフォルトではすべてのアクセスが拒否されます。開発者は特定の条件の下で、特定の操作(read、write、create、update、delete)へのアクセスを順次開放します。条件は、request.authによるユーザー認証、request.resourceによるリクエストデータ、resourceによる既存データをチェックできます。
// Firestoreアクセスルール
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// ユーザーは自分のデータのみを読み書きする
match /users/{userId} {
allow read, write: if
request.auth != null &&
request.auth.uid == userId;
}
// 認証されたユーザーは投稿を読める
match /posts/{postId} {
allow read: if request.auth != null;
allow create: if request.auth != null
&& request.resource.data.author == request.auth.uid;
}
}
}
アクセス制御に加えて、Security Rulesは書き込まれるデータの構造と型を検証できます。たとえば、メールフィールドが正規表現に一致するか、年齢が120歳を超えていないかを確認できます。検証は書き込み前に実行され、誤ったデータがサーバーに保存されるのを防ぎます。フィールド検証には、書き込まれているドキュメント全体を含むrequest.resource.dataオブジェクトが使用されます。
Firestoreは、クライアントアクセスなしでAdmin SDKを介したサーバー側書き込みのみが可能なコレクションもサポートしています。これは、ユーザーから見えるべきでないサービス情報、APIキー、設定を保存するのに便利です。これを行うには、ルールで該当するコレクションに対するすべてのクライアント操作を拒否し、サーバー側からのAdmin SDKを介したアクセスのみを許可します。
ToDoリストを作成するAndroidアプリケーションへのFirestore統合の例を見てみましょう。アプリケーションはリアルタイムでタスクを読み取り、新しいタスクを追加し、完了したタスクをマークします。非同期処理には、FirebaseのコールバックインターフェースとKotlinコルーチンが使用されます。
開始する前に、Firebase Consoleを介してプロジェクトをFirebaseに接続し、google-services.jsonファイルをアプリケーションモジュールに追加する必要があります。次に、build.gradleにfirebase-firestore-ktx依存関係とgoogle-servicesプラグインを追加します。ライブラリのバージョンは、すべてのFirebaseコンポーネントの互換性のために、現在のFirebase BoMバージョンに対応している必要があります。
dependencies {
// Firebase BoM — バージョン管理
implementation platform("com.google.firebase:firebase-bom:33.0.0")
implementation "com.google.firebase:firebase-firestore-ktx"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.9.0"
}
セットアップ後、TaskデータモデルとFirestoreを操作するためのリポジトリが作成されます。モデルには、id、title、isCompleted、timestampフィールドが含まれます。Firestoreはフィールド名をキーとして使用し、データクラスを自動的にドキュメントにシリアライズします。データの読み取りには、snapshotFlow拡張機能を介してFlowを返すスナップショットリスナーが使用されます。
data class Task(
val id: String = "",
val title: String = "",
val isCompleted: Boolean = false,
val createdAt: Timestamp? = null
)
class TaskRepository {
private val tasksRef = FirebaseFirestore
.getInstance()
.collection("tasks")
fun getTasks(): Flow<List<Task>> = tasksRef
.orderBy("createdAt", Query.Direction.DESCENDING)
.snapshotFlow()
.map { snapshot ->
snapshot?.toObjects(Task::class.java) ?: emptyList()
}
suspend fun addTask(title: String) {
tasksRef.add(Task(title = title))
}
}
ViewModelはリポジトリからのFlowを購読し、タスクリストをUIレベルに渡します。新しいタスクが追加されると、コルーチンスコープを介してリポジトリのsuspend関数が呼び出されます。Firestoreはすべてのクライアント間で変更を自動的に同期します。あるユーザーがタスクを追加すると、他のユーザーは画面を更新することなくリアルタイムで確認できます。
よくある質問
Firestoreは、柔軟なスキーマ、テーブルなし、JOINクエリなしのNoSQLデータベースです。データはテーブルの行ではなく、ドキュメントコレクションに保存されます。SQLとは異なり、Firestoreは事前定義されたスキーマを必要とせず、マイグレーションなしで自動的にスケーリングしますが、コレクション間の複雑なトランザクションクエリはサポートしていません。
Firestoreには generousな無料枠(Sparkプラン)があります:1日あたり50,000読み取り、20,000書き込み、20,000削除。それを超えると、従量課金制のBlazeプランが使用されます:$0.06/100,000読み取り、$0.18/100,000書き込み。料金は地域と転送データ量によって異なります。
Firestoreは競合解決にlast-write-wins戦略を使用します:ドキュメントへの最後の書き込みが以前のものを完全に置き換えます。より細かい制御のために、トランザクション(アトミック読み取り/書き込み操作)とバッチ書き込みが利用可能で、複数のドキュメントに対する操作の整合性を保証します。
はい、FirestoreはFirebase Consoleまたはgcloud CLIを介したデータのエクスポートとインポートをサポートしています。エクスポートはCloud Firestore Export形式で行われ、Google Cloud Storageに保存されます。データはFirebaseプロジェクト間で移行したり、BigQueryやその他のツールで分析するためにエクスポートしたりできます。
Firestoreには組み込みの全文検索はありません。このタスクには、GoogleはAlgoliaまたはMeilisearchとの統合、あるいはElasticsearchを使用したCloud Functionsを推奨しています。Firestoreの組み込みクエリは、等価チェック、範囲チェック、フィールド存在チェックのみをサポートし、部分文字列検索はできません。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。