1。概要
目標
このコードラボでは、CloudFirestoreをサポートするAndroid上にレストランおすすめアプリを作成します。次の方法を学習します:
- AndroidアプリからFirestoreへのデータの読み取りと書き込み
- Firestoreデータの変更をリアルタイムで聞く
- Firebase認証とセキュリティルールを使用してFirestoreデータを保護する
- 複雑なFirestoreクエリを作成する
前提条件
このコードラボを開始する前に、次のことを確認してください。
- AndroidStudio4.0以降
- API19以降を搭載したAndroidエミュレーター
- Node.jsバージョン10以降
- Javaバージョン8以降
2.Firebaseプロジェクトを作成します
- GoogleアカウントでFirebaseコンソールにログインします。
- Firebaseコンソールで、[プロジェクトの追加]をクリックします。
- 以下のスクリーンキャプチャに示されているように、Firebaseプロジェクトの名前(「FriendlyEats」など)を入力し、[続行]をクリックします。
- このコードラボの目的上、選択は重要ではないため、GoogleAnalyticsを有効にするように求められる場合があります。
- 1分ほどで、Firebaseプロジェクトの準備が整います。 [続行]をクリックします。
3.サンプルプロジェクトを設定します
コードをダウンロードする
次のコマンドを実行して、このコードラボのサンプルコードのクローンを作成します。これにより、マシン上にfriendlyeats-android
というフォルダが作成されます。
$ git clone https://github.com/firebase/friendlyeats-android
マシンにgitがない場合は、GitHubから直接コードをダウンロードすることもできます。
Firebase構成を追加する
- Firebaseコンソールで、左側のナビゲーションで[プロジェクトの概要]を選択します。 Androidボタンをクリックして、プラットフォームを選択します。パッケージ名の入力を求められたら、
com.google.firebase.example.fireeats
を使用します
- [アプリの登録]をクリックし、指示に従って
google-services.json
ファイルをダウンロードし、ダウンロードしたコードのapp/
フォルダーに移動します。次に、[次へ]をクリックします。
プロジェクトをインポートする
AndroidStudioを開きます。 [ファイル]>[新規]>[プロジェクトのインポート]をクリックして、 friendlyeats-androidフォルダーを選択します。
4.Firebaseエミュレータをセットアップします
このコードラボでは、 Firebase Emulator Suiteを使用して、CloudFirestoreやその他のFirebaseサービスをローカルでエミュレートします。これにより、アプリを構築するための安全で高速な無料のローカル開発環境が提供されます。
FirebaseCLIをインストールします
まず、 FirebaseCLIをインストールする必要があります。 macOSまたはLinuxを使用している場合は、次のcURLコマンドを実行できます。
curl -sL https://firebase.tools | bash
Windowsを使用している場合は、インストール手順を読んでスタンドアロンバイナリを取得するか、 npm
を介してインストールしてください。
CLIをインストールしたら、 firebase --version
を実行すると、 9.0.0
以降のバージョンが報告されます。
$ firebase --version 9.0.0
ログインする
firebase login
を実行して、CLIをGoogleアカウントに接続します。これにより、新しいブラウザウィンドウが開き、ログインプロセスが完了します。以前にFirebaseプロジェクトを作成したときに使用したものと同じアカウントを選択してください。
プロジェクトをリンクする
friendeats friendlyeats-android
フォルダー内からfirebase use --add
を実行し、-addを使用してローカルプロジェクトをFirebaseプロジェクトに接続します。プロンプトに従って、前に作成したプロジェクトを選択し、エイリアスを選択するように求められた場合は、 default
を入力します。
5.アプリを実行します
次に、FirebaseEmulatorSuiteとFriendlyEatsAndroidアプリを初めて実行します。
エミュレーターを実行します
ターミナルで、 friendlyeats-android
ディレクトリ内からfirebase emulators:start
を実行してFirebaseEmulatorsを起動します。次のようなログが表示されます。
$ firebase emulators:start i emulators: Starting emulators: auth, firestore i firestore: Firestore Emulator logging to firestore-debug.log i ui: Emulator UI logging to ui-debug.log ┌─────────────────────────────────────────────────────────────┐ │ ✔ All emulators ready! It is now safe to connect your app. │ │ i View Emulator UI at http://localhost:4000 │ └─────────────────────────────────────────────────────────────┘ ┌────────────────┬────────────────┬─────────────────────────────────┐ │ Emulator │ Host:Port │ View in Emulator UI │ ├────────────────┼────────────────┼─────────────────────────────────┤ │ Authentication │ localhost:9099 │ http://localhost:4000/auth │ ├────────────────┼────────────────┼─────────────────────────────────┤ │ Firestore │ localhost:8080 │ http://localhost:4000/firestore │ └────────────────┴────────────────┴─────────────────────────────────┘ Emulator Hub running at localhost:4400 Other reserved ports: 4500 Issues? Report them at https://github.com/firebase/firebase-tools/issues and attach the *-debug.log files.
これで、マシン上で実行されている完全なローカル開発環境ができました。コードラボの残りの部分では、このコマンドを実行したままにしてください。Androidアプリはエミュレーターに接続する必要があります。
アプリをエミュレーターに接続します
AndroidStudioでファイルFirebaseUtil.java
を開きます。このファイルには、FirebaseSDKをマシンで実行されているローカルエミュレーターに接続するためのロジックが含まれています。
ファイルの先頭で、次の行を調べます。
/** Use emulators only in debug builds **/
private static final boolean sUseEmulators = BuildConfig.DEBUG;
BuildConfig
を使用して、アプリがdebug
モードで実行されている場合にのみエミュレーターに接続するようにしています。アプリをrelease
モードでコンパイルすると、この条件はfalseになります。
次に、 getFirestore()
メソッドを見てみましょう。
public static FirebaseFirestore getFirestore() {
if (FIRESTORE == null) {
FIRESTORE = FirebaseFirestore.getInstance();
// Connect to the Cloud Firestore emulator when appropriate. The host '10.0.2.2' is a
// special IP address to let the Android emulator connect to 'localhost'.
if (sUseEmulators) {
FIRESTORE.useEmulator("10.0.2.2", 8080);
}
}
return FIRESTORE;
}
useEmulator(host, port)
メソッドを使用してFirebaseSDKをローカルのFirestoreエミュレーターに接続していることがわかります。アプリ全体で、 FirebaseUtil.getFirestore()
を使用してFirebaseFirestore
のこのインスタンスにアクセスするため、 debug
モードで実行しているときは常にFirestoreエミュレーターに接続していることを確認します。
アプリを実行する
google-services.json
ファイルを適切に追加した場合、プロジェクトはコンパイルされます。 Android Studioで、[ビルド]> [プロジェクトの再ビルド]をクリックし、エラーが残っていないことを確認します。
AndroidStudioの場合Androidエミュレーターでアプリを実行します。最初に、「サインイン」画面が表示されます。任意のメールアドレスとパスワードを使用してアプリにサインインできます。このサインインプロセスはFirebaseAuthenticationエミュレータに接続しているため、実際の認証情報は送信されていません。
次に、Webブラウザでhttp:// localhost:4000に移動して、エミュレータUIを開きます。次に、[認証]タブをクリックすると、作成したアカウントが表示されます。
サインインプロセスが完了すると、アプリのホーム画面が表示されます。
すぐに、ホーム画面に入力するデータを追加します。
6.Firestoreにデータを書き込みます
このセクションでは、現在空のホーム画面にデータを入力できるように、Firestoreにデータを書き込みます。
このアプリの主なモデルオブジェクトはレストランです( model/Restaurant.java
を参照)。 Firestoreデータは、ドキュメント、コレクション、およびサブコレクションに分割されます。各レストランは、 "restaurants"
と呼ばれるトップレベルのコレクションにドキュメントとして保存されます。 Firestoreデータモデルの詳細については、ドキュメントのドキュメントとコレクションについてお読みください。
デモンストレーションの目的で、オーバーフローメニューの[ランダムアイテムの追加]ボタンをクリックすると、アプリに10個のランダムレストランを作成する機能が追加されます。 MainActivity.java
ファイルを開き、 onAddItemsClicked()
メソッドの内容を次のように置き換えます。
private void onAddItemsClicked() {
// Get a reference to the restaurants collection
CollectionReference restaurants = mFirestore.collection("restaurants");
for (int i = 0; i < 10; i++) {
// Get a random Restaurant POJO
Restaurant restaurant = RestaurantUtil.getRandom(this);
// Add a new document to the restaurants collection
restaurants.add(restaurant);
}
}
上記のコードについて注意すべき重要な点がいくつかあります。
- まず、
"restaurants"
コレクションへの参照を取得しました。コレクションはドキュメントが追加されるときに暗黙的に作成されるため、データを書き込む前にコレクションを作成する必要はありませんでした。 - ドキュメントは、各レストランドキュメントの作成に使用するPOJO(Plain Old Java Object)を使用して作成できます。
-
add()
メソッドは、自動生成されたIDを持つコレクションにドキュメントを追加するため、レストランごとに一意のIDを指定する必要はありませんでした。
次に、アプリを再度実行し、オーバーフローメニュー(右上隅)の[ランダムアイテムの追加]ボタンをクリックして、作成したコードを呼び出します。
次に、Webブラウザでhttp:// localhost:4000に移動して、エミュレータUIを開きます。次に、[ Firestore ]タブをクリックすると、追加したデータが表示されます。
このデータは、マシンに対して100%ローカルです。実際、実際のプロジェクトにはまだFirestoreデータベースが含まれていません。これは、結果なしにこのデータを変更および削除して実験するのが安全であることを意味します。
おめでとうございます。Firestoreにデータを書き込んだだけです。次のステップでは、このデータをアプリに表示する方法を学習します。
7.Firestoreからのデータを表示します
このステップでは、Firestoreからデータを取得してアプリに表示する方法を学習します。 Firestoreからデータを読み取るための最初のステップは、 Query
を作成することです。 MainActivity.java
ファイルを開き、 onCreate()
メソッドの先頭に次のコードを追加します。
mFirestore = FirebaseUtil.getFirestore();
// Get the 50 highest rated restaurants
mQuery = mFirestore.collection("restaurants")
.orderBy("avgRating", Query.Direction.DESCENDING)
.limit(LIMIT);
次に、クエリをリッスンして、一致するすべてのドキュメントを取得し、将来の更新がリアルタイムで通知されるようにします。最終的な目標はこのデータをRecyclerView
にバインドすることであるため、データをリッスンするためにRecyclerView.Adapter
クラスを作成する必要があります。
すでに部分的に実装されているFirestoreAdapter
クラスを開きます。まず、アダプタにEventListener
を実装させ、Firestoreクエリの更新を受信できるようにonEvent
関数を定義しましょう。
public abstract class FirestoreAdapter<VH extends RecyclerView.ViewHolder>
extends RecyclerView.Adapter<VH>
implements EventListener<QuerySnapshot> { // Add this "implements"
// ...
// Add this method
@Override
public void onEvent(QuerySnapshot documentSnapshots,
FirebaseFirestoreException e) {
// Handle errors
if (e != null) {
Log.w(TAG, "onEvent:error", e);
return;
}
// Dispatch the event
for (DocumentChange change : documentSnapshots.getDocumentChanges()) {
// Snapshot of the changed document
DocumentSnapshot snapshot = change.getDocument();
switch (change.getType()) {
case ADDED:
// TODO: handle document added
break;
case MODIFIED:
// TODO: handle document modified
break;
case REMOVED:
// TODO: handle document removed
break;
}
}
onDataChanged();
}
// ...
}
初期ロード時に、リスナーは新しいドキュメントごとに1つのADDED
イベントを受け取ります。クエリの結果セットが時間の経過とともに変化すると、リスナーはその変化を含むより多くのイベントを受け取ります。それでは、リスナーの実装を終了しましょう。最初に、 onDocumentAdded
、 onDocumentModified
、およびonDocumentRemoved
の3つの新しいメソッドを追加します。
protected void onDocumentAdded(DocumentChange change) {
mSnapshots.add(change.getNewIndex(), change.getDocument());
notifyItemInserted(change.getNewIndex());
}
protected void onDocumentModified(DocumentChange change) {
if (change.getOldIndex() == change.getNewIndex()) {
// Item changed but remained in same position
mSnapshots.set(change.getOldIndex(), change.getDocument());
notifyItemChanged(change.getOldIndex());
} else {
// Item changed and changed position
mSnapshots.remove(change.getOldIndex());
mSnapshots.add(change.getNewIndex(), change.getDocument());
notifyItemMoved(change.getOldIndex(), change.getNewIndex());
}
}
protected void onDocumentRemoved(DocumentChange change) {
mSnapshots.remove(change.getOldIndex());
notifyItemRemoved(change.getOldIndex());
}
次に、 onEvent
からこれらの新しいメソッドを呼び出します。
@Override
public void onEvent(QuerySnapshot documentSnapshots,
FirebaseFirestoreException e) {
// ...
// Dispatch the event
for (DocumentChange change : documentSnapshots.getDocumentChanges()) {
// Snapshot of the changed document
DocumentSnapshot snapshot = change.getDocument();
switch (change.getType()) {
case ADDED:
onDocumentAdded(change); // Add this line
break;
case MODIFIED:
onDocumentModified(change); // Add this line
break;
case REMOVED:
onDocumentRemoved(change); // Add this line
break;
}
}
onDataChanged();
}
最後に、 startListening()
メソッドを実装して、リスナーをアタッチします。
public void startListening() {
if (mQuery != null && mRegistration == null) {
mRegistration = mQuery.addSnapshotListener(this);
}
}
これで、アプリはFirestoreからデータを読み取るように完全に構成されました。アプリを再度実行すると、前の手順で追加したレストランが表示されます。
次に、ブラウザのエミュレータUIに戻り、レストラン名の1つを編集します。あなたはそれがアプリでほぼ瞬時に変化するのを見るはずです!
8.データの並べ替えとフィルタリング
このアプリは現在、コレクション全体で一流のレストランを表示していますが、実際のレストランアプリでは、ユーザーはデータを並べ替えてフィルタリングする必要があります。たとえば、アプリは「フィラデルフィアのトップシーフードレストラン」または「最も安価なピザ」を表示できる必要があります。
アプリの上部にある白いバーをクリックすると、フィルターダイアログが表示されます。このセクションでは、Firestoreクエリを使用してこのダイアログを機能させます。
MainActivity.javaのMainActivity.java
onFilter()
メソッドを編集してみましょう。このメソッドは、フィルターダイアログの出力をキャプチャするために作成したヘルパーオブジェクトであるFilters
オブジェクトを受け入れます。このメソッドを変更して、フィルターからクエリを作成します。
@Override
public void onFilter(Filters filters) {
// Construct basic query
Query query = mFirestore.collection("restaurants");
// Category (equality filter)
if (filters.hasCategory()) {
query = query.whereEqualTo("category", filters.getCategory());
}
// City (equality filter)
if (filters.hasCity()) {
query = query.whereEqualTo("city", filters.getCity());
}
// Price (equality filter)
if (filters.hasPrice()) {
query = query.whereEqualTo("price", filters.getPrice());
}
// Sort by (orderBy with direction)
if (filters.hasSortBy()) {
query = query.orderBy(filters.getSortBy(), filters.getSortDirection());
}
// Limit items
query = query.limit(LIMIT);
// Update the query
mQuery = query;
mAdapter.setQuery(query);
// Set header
mCurrentSearchView.setText(Html.fromHtml(filters.getSearchDescription(this)));
mCurrentSortByView.setText(filters.getOrderDescription(this));
// Save filters
mViewModel.setFilters(filters);
}
上記のスニペットでは、指定されたフィルターに一致するwhere
句とorderBy
句を付加して、 Query
オブジェクトを作成します。
アプリを再度実行し、次のフィルターを選択して、最も人気のある低価格のレストランを表示します。
これで、低価格のオプションのみを含むレストランのフィルターされたリストが表示されます。
ここまで進んだら、Firestoreで完全に機能するレストランおすすめの表示アプリを作成できました。レストランをリアルタイムで並べ替えてフィルタリングできるようになりました。次のいくつかのセクションでは、レストランにレビューを追加し、アプリにセキュリティルールを追加します。
9.サブコレクションでデータを整理します
このセクションでは、アプリに評価を追加して、ユーザーがお気に入りの(または最も嫌いな)レストランを確認できるようにします。
コレクションとサブコレクション
これまで、すべてのレストランデータを「レストラン」と呼ばれるトップレベルのコレクションに保存してきました。ユーザーがレストランを評価するときに、新しいRating
オブジェクトをレストランに追加します。このタスクでは、サブコレクションを使用します。サブコレクションは、ドキュメントに添付されているコレクションと考えることができます。したがって、各レストランドキュメントには、評価ドキュメントでいっぱいの評価サブコレクションがあります。サブコレクションは、ドキュメントを肥大化させたり、複雑なクエリを必要とせずにデータを整理するのに役立ちます。
サブコレクションにアクセスするには、親ドキュメントで.collection()
を呼び出します。
CollectionReference subRef = mFirestore.collection("restaurants")
.document("abc123")
.collection("ratings");
トップレベルのコレクションと同じようにサブコレクションにアクセスしてクエリを実行できます。サイズの制限やパフォーマンスの変更はありません。 Firestoreデータモデルの詳細については、こちらをご覧ください。
トランザクションでのデータの書き込み
適切なサブコレクションにRating
を追加するには、 .add()
を呼び出すだけですが、新しいデータを反映するために、 Restaurant
オブジェクトの平均評価と評価数も更新する必要があります。これらの2つの変更を行うために別々の操作を使用する場合、データが古くなったり不正確になったりする可能性のある競合状態がいくつかあります。
評価が適切に追加されるようにするために、トランザクションを使用してレストランに評価を追加します。このトランザクションは、いくつかのアクションを実行します。
- レストランの現在の評価を読み、新しい評価を計算します
- サブコレクションに評価を追加します
- レストランの平均評価と評価数を更新する
RestaurantDetailActivity.java
を開き、 addRating
関数を実装します。
private Task<Void> addRating(final DocumentReference restaurantRef,
final Rating rating) {
// Create reference for new rating, for use inside the transaction
final DocumentReference ratingRef = restaurantRef.collection("ratings")
.document();
// In a transaction, add the new rating and update the aggregate totals
return mFirestore.runTransaction(new Transaction.Function<Void>() {
@Override
public Void apply(Transaction transaction)
throws FirebaseFirestoreException {
Restaurant restaurant = transaction.get(restaurantRef)
.toObject(Restaurant.class);
// Compute new number of ratings
int newNumRatings = restaurant.getNumRatings() + 1;
// Compute new average rating
double oldRatingTotal = restaurant.getAvgRating() *
restaurant.getNumRatings();
double newAvgRating = (oldRatingTotal + rating.getRating()) /
newNumRatings;
// Set new restaurant info
restaurant.setNumRatings(newNumRatings);
restaurant.setAvgRating(newAvgRating);
// Commit to Firestore
transaction.set(restaurantRef, restaurant);
transaction.set(ratingRef, rating);
return null;
}
});
}
addRating()
関数は、トランザクション全体を表すTask
を返します。 onRating()
関数では、トランザクションの結果に応答するリスナーがタスクに追加されます。
次に、アプリをもう一度実行して、レストランの1つをクリックすると、レストランの詳細画面が表示されます。 +ボタンをクリックして、レビューの追加を開始します。星の数を選び、テキストを入力してレビューを追加します。
[送信]をクリックすると、トランザクションが開始されます。トランザクションが完了すると、以下にレビューが表示され、レストランのレビュー数が更新されます。
おめでとうございます!これで、CloudFirestore上に構築されたソーシャルなローカルのモバイルレストランレビューアプリができました。最近はとても人気があるそうです。
10.データを保護します
これまでのところ、このアプリケーションのセキュリティについては考慮していません。ユーザーが正しい自分のデータしか読み書きできないことをどうやって知ることができますか? Firestoreデータベースは、セキュリティルールと呼ばれる構成ファイルによって保護されています。
firestore.rules
ファイルを開くと、次のように表示されます。
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
//
// WARNING: These rules are insecure! We will replace them with
// more secure rules later in the codelab
//
allow read, write: if request.auth != null;
}
}
}
これらのルールを変更して、不要なデータへのアクセスや変更を防ぎ、 firestore.rules
ファイルを開いて、コンテンツを次のように置き換えましょう。
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Determine if the value of the field "key" is the same
// before and after the request.
function isUnchanged(key) {
return (key in resource.data)
&& (key in request.resource.data)
&& (resource.data[key] == request.resource.data[key]);
}
// Restaurants
match /restaurants/{restaurantId} {
// Any signed-in user can read
allow read: if request.auth != null;
// Any signed-in user can create
// WARNING: this rule is for demo purposes only!
allow create: if request.auth != null;
// Updates are allowed if no fields are added and name is unchanged
allow update: if request.auth != null
&& (request.resource.data.keys() == resource.data.keys())
&& isUnchanged("name");
// Deletes are not allowed.
// Note: this is the default, there is no need to explicitly state this.
allow delete: if false;
// Ratings
match /ratings/{ratingId} {
// Any signed-in user can read
allow read: if request.auth != null;
// Any signed-in user can create if their uid matches the document
allow create: if request.auth != null
&& request.resource.data.userId == request.auth.uid;
// Deletes and updates are not allowed (default)
allow update, delete: if false;
}
}
}
}
これらのルールはアクセスを制限して、クライアントが安全な変更のみを行うようにします。たとえば、レストランのドキュメントを更新すると、評価のみが変更され、名前やその他の不変のデータは変更されません。レーティングは、ユーザーIDがサインインしたユーザーと一致する場合にのみ作成できます。これにより、なりすましが防止されます。
セキュリティルールの詳細については、ドキュメントをご覧ください。
11.結論
これで、Firestore上にフル機能のアプリが作成されました。次のような最も重要なFirestoreの機能について学びました。
- ドキュメントとコレクション
- データの読み取りと書き込み
- クエリによる並べ替えとフィルタリング
- サブコレクション
- トランザクション
もっと詳しく知る
Firestoreについて学び続けるために、ここに始めるためのいくつかの良い場所があります:
このコードラボのレストランアプリは、「FriendlyEats」サンプルアプリケーションに基づいています。ここでそのアプリのソースコードを閲覧できます。
オプション:本番環境にデプロイする
これまでのところ、このアプリはFirebaseEmulatorSuiteのみを使用しています。このアプリを実際のFirebaseプロジェクトにデプロイする方法を学びたい場合は、次の手順に進んでください。
12.(オプション)アプリをデプロイします
これまでのところ、このアプリは完全にローカルであり、すべてのデータはFirebaseEmulatorSuiteに含まれています。このセクションでは、このアプリが本番環境で動作するようにFirebaseプロジェクトを設定する方法を学習します。
Firebase認証
Firebaseコンソールで[認証]セクションに移動し、[開始]をクリックします。 [サインイン方法]タブに移動し、ネイティブプロバイダーから[電子メール/パスワード]オプションを選択します。
電子メール/パスワードのサインイン方法を有効にして、[保存]をクリックします。
ファイヤーストア
データベースを作成する
コンソールの[ Firestoreデータベース]セクションに移動し、[データベースの作成]をクリックします。
- セキュリティルールについてプロンプトが表示されたら、本番モードで開始することを選択します。これらのルールはまもなく更新されます。
- アプリに使用するデータベースの場所を選択します。データベースの場所の選択は永続的な決定であり、それを変更するには、新しいプロジェクトを作成する必要があることに注意してください。プロジェクトの場所の選択の詳細については、ドキュメントを参照してください。
ルールの展開
以前に作成したセキュリティルールを展開するには、codelabディレクトリで次のコマンドを実行します。
$ firebase deploy --only firestore:rules
これにより、 firestore.rules
のコンテンツがプロジェクトにデプロイされます。これは、コンソールの[ルール]タブに移動して確認できます。
インデックスのデプロイ
FriendlyEatsアプリには複雑な並べ替えとフィルタリングがあり、多数のカスタム複合インデックスが必要です。これらはFirebaseコンソールで手動で作成できますが、 firestore.indexes.json
ファイルに定義を記述し、FirebaseCLIを使用してデプロイする方が簡単です。
firestore.indexes.json
ファイルを開くと、必要なインデックスがすでに提供されていることがわかります。
{
"indexes": [
{
"collectionId": "restaurants",
"queryScope": "COLLECTION",
"fields": [
{ "fieldPath": "city", "mode": "ASCENDING" },
{ "fieldPath": "avgRating", "mode": "DESCENDING" }
]
},
{
"collectionId": "restaurants",
"queryScope": "COLLECTION",
"fields": [
{ "fieldPath": "category", "mode": "ASCENDING" },
{ "fieldPath": "avgRating", "mode": "DESCENDING" }
]
},
{
"collectionId": "restaurants",
"queryScope": "COLLECTION",
"fields": [
{ "fieldPath": "price", "mode": "ASCENDING" },
{ "fieldPath": "avgRating", "mode": "DESCENDING" }
]
},
{
"collectionId": "restaurants",
"queryScope": "COLLECTION",
"fields": [
{ "fieldPath": "city", "mode": "ASCENDING" },
{ "fieldPath": "numRatings", "mode": "DESCENDING" }
]
},
{
"collectionId": "restaurants",
"queryScope": "COLLECTION",
"fields": [
{ "fieldPath": "category", "mode": "ASCENDING" },
{ "fieldPath": "numRatings", "mode": "DESCENDING" }
]
},
{
"collectionId": "restaurants",
"queryScope": "COLLECTION",
"fields": [
{ "fieldPath": "price", "mode": "ASCENDING" },
{ "fieldPath": "numRatings", "mode": "DESCENDING" }
]
},
{
"collectionId": "restaurants",
"queryScope": "COLLECTION",
"fields": [
{ "fieldPath": "city", "mode": "ASCENDING" },
{ "fieldPath": "price", "mode": "ASCENDING" }
]
},
{
"collectionId": "restaurants",
"fields": [
{ "fieldPath": "category", "mode": "ASCENDING" },
{ "fieldPath": "price", "mode": "ASCENDING" }
]
}
],
"fieldOverrides": []
}
これらのインデックスを展開するには、次のコマンドを実行します。
$ firebase deploy --only firestore:indexes
インデックスの作成は瞬時ではないことに注意してください。Firebaseコンソールで進行状況を監視できます。
アプリを構成する
FirebaseUtil
クラスでは、デバッグモードのときにエミュレーターに接続するようにFirebaseSDKを構成しました。
public class FirebaseUtil {
/** Use emulators only in debug builds **/
private static final boolean sUseEmulators = BuildConfig.DEBUG;
// ...
}
実際のFirebaseプロジェクトでアプリをテストする場合は、次のいずれかを実行できます。
- リリースモードでアプリをビルドし、デバイスで実行します。
- 一時的に
sUseEmulators
をfalse
に変更し、アプリを再実行します。
本番環境に正しく接続するには、アプリからサインアウトしてから再度サインインする必要がある場合があることに注意してください。