Google se compromete a impulsar la igualdad racial para las comunidades afrodescendientes. Obtén información al respecto.
Se usó la API de Cloud Translation para traducir esta página.
Switch to English

Codelab para Android de Cloud Firestore

Metas

En este laboratorio de código, creará una aplicación de recomendación de restaurantes en Android respaldada por Cloud Firestore. Aprenderá a:

  • Leer y escribir datos en Firestore desde una aplicación de Android
  • Escuche los cambios en los datos de Firestore en tiempo real
  • Use la autenticación de Firebase y las reglas de seguridad para proteger los datos de Firestore
  • Escribe consultas complejas de Firestore

Prerrequisitos

Antes de iniciar este laboratorio de código, asegúrese de tener:

  • Android Studio 4.0 o superior
  • Un emulador de Android
  • Node.js versión 10 o superior
  • Java versión 8 o superior
  1. Inicie sesión en la consola de Firebase con su cuenta de Google.
  2. En Firebase console , haz clic en Agregar proyecto .
  3. Como se muestra en la captura de pantalla a continuación, ingrese un nombre para su proyecto de Firebase (por ejemplo, "Friendly Eats") y haga clic en Continuar .

9d2f625aebcab6af.png

  1. Es posible que se le solicite que habilite Google Analytics, para los fines de este laboratorio de código, su selección no importa.
  2. Después de aproximadamente un minuto, su proyecto de Firebase estará listo. Haga clic en Continuar .

Descarga el código

Ejecute el siguiente comando para clonar el código de muestra para este laboratorio de código. Esto creará una carpeta llamada friendlyeats-android en su máquina:

$ git clone https://github.com/firebase/friendlyeats-android

Si no tiene git en su máquina, también puede descargar el código directamente desde GitHub.

Importa el proyecto a Android Studio. Probablemente verá algunos errores de compilación o tal vez una advertencia sobre la falta de un archivo google-services.json . Corregiremos esto en la siguiente sección.

Agregar configuración de Firebase

  1. En Firebase console , seleccione Descripción general del proyecto en el panel de navegación izquierdo. Haga clic en el botón de Android para seleccionar la plataforma. Cuando se le solicite un nombre de paquete, use com.google.firebase.example.fireeats

73d151ed16016421.png

  1. Haga clic en Registrar aplicación y siga las instrucciones para descargar el archivo google-services.json y moverlo a la app/ carpeta del código de muestra. Luego haga clic en Siguiente .

En este laboratorio de código, usará Firebase Emulator Suite para emular localmente Cloud Firestore y otros servicios de Firebase. Esto proporciona un entorno de desarrollo local seguro, rápido y gratuito para crear su aplicación.

Instala Firebase CLI

Primero deberá instalar Firebase CLI . La forma más sencilla de hacer esto es usar npm :

npm install -g firebase-tools

Si no tiene npm o experimenta un error, lea las instrucciones de instalación para obtener un binario independiente para su plataforma.

Una vez que haya instalado la CLI, ejecutar firebase --version debería informar una versión de 9.0.0 o superior:

$ firebase --version
9.0.0

Iniciar sesión

Ejecute firebase login para conectar la CLI a su cuenta de Google. Esto abrirá una nueva ventana del navegador para completar el proceso de inicio de sesión. Asegúrese de elegir la misma cuenta que usó al crear su proyecto de Firebase anteriormente.

Desde dentro de la carpeta friendlyeats-android ejecute firebase use --add para conectar su proyecto local a su proyecto de Firebase. Siga las instrucciones para seleccionar el proyecto que creó anteriormente y, si se le solicita que elija un alias, ingrese el default .

Ahora es el momento de ejecutar Firebase Emulator Suite y la aplicación de Android FriendlyEats por primera vez.

Ejecuta los emuladores

En su terminal desde el directorio friendlyeats-android , ejecute los firebase emulators:start a iniciar los emuladores de Firebase. Debería ver registros como este:

$ 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.

¡Ahora tiene un entorno de desarrollo local completo ejecutándose en su máquina! Asegúrese de dejar este comando en ejecución durante el resto del laboratorio de código, su aplicación de Android deberá conectarse a los emuladores.

Conecte la aplicación a los emuladores

Abra el archivo FirebaseUtil.java en Android Studio. Este archivo contiene la lógica para conectar los SDK de Firebase a los emuladores locales que se ejecutan en su máquina.

En la parte superior del archivo, examine esta línea:

    /** Use emulators only in debug builds **/
    private static final boolean sUseEmulators = BuildConfig.DEBUG;

Estamos usando BuildConfig para asegurarnos de que solo nos conectamos a los emuladores cuando nuestra aplicación se ejecuta en modo de debug . Cuando compilemos la aplicación en modo de release , esta condición será falsa.

Ahora eche un vistazo al método 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;
    }

Podemos ver que está usando el useEmulator(host, port) para conectar el SDK de Firebase al emulador local de Firestore. En toda la aplicación usaremos FirebaseUtil.getFirestore() para acceder a esta instancia de FirebaseFirestore por lo que estamos seguros de que siempre nos estamos conectando al emulador de Firestore cuando se ejecuta en modo de debug .

Ejecutar la aplicación

Si agregó correctamente el archivo google-services.json , el proyecto debería compilarse ahora. En Android Studio, haga clic en Compilar > Reconstruir proyecto y asegúrese de que no queden errores.

En Android Studio Ejecute la aplicación en su emulador de Android. Al principio se le presentará una pantalla de "Iniciar sesión". Puede utilizar cualquier correo electrónico y contraseña para iniciar sesión en la aplicación. Este proceso de inicio de sesión se conecta al emulador de Firebase Authentication, por lo que no se transmiten credenciales reales.

Ahora abra la interfaz de usuario de emuladores navegando a http: // localhost: 4000 en su navegador web. Luego haga clic en la pestaña Autenticación y debería ver la cuenta que acaba de crear:

Emulador de autenticación de Firebase

Una vez que haya completado el proceso de inicio de sesión, debería ver la pantalla de inicio de la aplicación:

de06424023ffb4b9.png

Pronto agregaremos algunos datos para completar la pantalla de inicio.

En esta sección, escribiremos algunos datos en Firestore para que podamos completar la pantalla de inicio actualmente vacía.

El objeto principal del modelo en nuestra aplicación es un restaurante (ver model/Restaurant.java ). Los datos de Firestore se dividen en documentos, colecciones y subcolecciones. Almacenaremos cada restaurante como un documento en una colección de alto nivel llamada "restaurants" . Para obtener más información sobre el modelo de datos de Firestore, lea sobre documentos y colecciones en la documentación .

Para fines de demostración, agregaremos funcionalidad en la aplicación para crear diez restaurantes aleatorios cuando hagamos clic en el botón "Agregar elementos aleatorios" en el menú adicional. Abra el archivo MainActivity.java y complete el método 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);
        }
    }

Hay algunas cosas importantes a tener en cuenta sobre el código anterior:

  • Comenzamos obteniendo una referencia a la colección "restaurants" . Las colecciones se crean implícitamente cuando se agregan documentos, por lo que no era necesario crear la colección antes de escribir datos.
  • Los documentos se pueden crear utilizando POJO, que usamos para crear cada documento de restaurante.
  • El método add() agrega un documento a una colección con una identificación generada automáticamente, por lo que no necesitamos especificar una identificación única para cada restaurante.

Ahora ejecute la aplicación nuevamente y haga clic en el botón "Agregar elementos aleatorios" en el menú adicional para invocar el código que acaba de escribir:

95691e9b71ba55e3.png

Ahora abra la interfaz de usuario de Emulators navegando a http: // localhost: 4000 en su navegador web. Luego haga clic en la pestaña Firestore y debería ver los datos que acaba de agregar:

Emulador de autenticación de Firebase

Estos datos son 100% locales para su máquina. De hecho, ¡tu proyecto real ni siquiera contiene una base de datos de Firestore todavía! Esto significa que es seguro experimentar modificando y eliminando estos datos sin consecuencias.

¡Felicitaciones, acaba de escribir datos en Firestore! En el siguiente paso, aprenderemos cómo mostrar estos datos en la aplicación.

En este paso, aprenderemos cómo recuperar datos de Firestore y mostrarlos en nuestra aplicación. El primer paso para leer datos de Firestore es crear una Query . Modifique el método onCreate() :

        mFirestore = FirebaseUtil.getFirestore();

        // Get the 50 highest rated restaurants
        mQuery = mFirestore.collection("restaurants")
                .orderBy("avgRating", Query.Direction.DESCENDING)
                .limit(LIMIT);

Ahora queremos escuchar la consulta, para obtener todos los documentos coincidentes y recibir notificaciones de futuras actualizaciones en tiempo real. Debido a que nuestro objetivo final es vincular estos datos a un RecyclerView , necesitamos crear una clase RecyclerView.Adapter para escuchar los datos.

Abra la clase FirestoreAdapter , que ya se implementó parcialmente. Primero, hagamos que el adaptador implemente EventListener y definamos la función onEvent para que pueda recibir actualizaciones de una consulta de Firestore:

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();
    }

  // ...
}

En la carga inicial, el oyente recibirá un evento ADDED por cada nuevo documento. A medida que el conjunto de resultados de la consulta cambia con el tiempo, el oyente recibirá más eventos que contengan los cambios. Ahora terminemos de implementar el oyente. Primero agregue tres nuevos métodos: onDocumentAdded , onDocumentModified y on onDocumentRemoved :

    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());
    }

Luego llame a estos nuevos métodos desde 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();
    }

Finalmente, implemente el método startListening() para adjuntar el oyente:

    public void startListening() {
        if (mQuery != null && mRegistration == null) {
            mRegistration = mQuery.addSnapshotListener(this);
        }
    }

Ahora la aplicación está completamente configurada para leer datos de Firestore. Ejecute la aplicación nuevamente y debería ver los restaurantes que agregó en el paso anterior:

9e45f40faefce5d0.png

Ahora regrese a la interfaz de usuario del emulador en su navegador y edite uno de los nombres de los restaurantes. ¡Debería verlo cambiar en la aplicación casi al instante!

Actualmente, la aplicación muestra los restaurantes mejor calificados en toda la colección, pero en una aplicación de restaurante real, el usuario querría ordenar y filtrar los datos. Por ejemplo, la aplicación debería poder mostrar "Los mejores restaurantes de mariscos en Filadelfia" o "La pizza menos cara".

Al hacer clic en la barra blanca en la parte superior de la aplicación, aparece un cuadro de diálogo de filtros. En esta sección usaremos consultas de Firestore para que este diálogo funcione:

67898572a35672a5.png

onFilter() método onFilter() de MainActivity.java . Este método acepta un objeto Filters que es un objeto auxiliar que creamos para capturar la salida del diálogo de filtros. Cambiaremos este método para construir una consulta a partir de los filtros:

    @Override
    public void onFilter(Filters filters) {
        // Construct query 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);
    }

En el fragmento anterior construimos una Query objeto uniendo where y orderBy cláusulas para que coincida con los filtros indicados.

Ejecute la aplicación nuevamente y seleccione el siguiente filtro para mostrar los restaurantes de bajo precio más populares:

7a67a8a400c80c50.png

Ahora debería ver una lista filtrada de restaurantes que contiene solo opciones de bajo precio:

a670188398c3c59.png

Si ha llegado hasta aquí, ¡ahora ha creado una aplicación de visualización de recomendaciones de restaurantes en pleno funcionamiento en Firestore! Ahora puede ordenar y filtrar restaurantes en tiempo real. En las siguientes secciones, publicaremos reseñas y seguridad en la aplicación.

En esta sección, agregaremos calificaciones a la aplicación para que los usuarios puedan revisar sus restaurantes favoritos (o menos favoritos).

Colecciones y subcolecciones

Hasta ahora, hemos almacenado todos los datos de los restaurantes en una colección de alto nivel llamada "restaurantes". Cuando un usuario califica un restaurante, queremos agregar un nuevo objeto de Rating a los restaurantes. Para esta tarea usaremos una subcolección. Puede pensar en una subcolección como una colección que se adjunta a un documento. Por lo tanto, cada documento de restaurante tendrá una subcolección de calificaciones llena de documentos de calificación. Las subcolecciones ayudan a organizar los datos sin sobrecargar nuestros documentos ni requerir consultas complejas.

Para acceder a una subcolección, llame a .collection() en el documento principal:

CollectionReference subRef = mFirestore.collection("restaurants")
        .document("abc123")
        .collection("ratings");

Puede acceder y consultar una subcolección al igual que con una colección de nivel superior, no hay limitaciones de tamaño ni cambios de rendimiento. Puede leer más sobre el modelo de datos de Firestore aquí .

Escribir datos en una transacción

Agregar una Rating a la subcolección adecuada solo requiere llamar a .add() , pero también necesitamos actualizar la calificación promedio del objeto Restaurant y el número de calificaciones para reflejar los nuevos datos. Si utilizamos operaciones independientes para realizar estos dos cambios, hay una serie de condiciones de carrera que podrían resultar en datos obsoletos o incorrectos.

Para garantizar que las calificaciones se agreguen correctamente, utilizaremos una transacción para agregar calificaciones a un restaurante. Esta transacción realizará algunas acciones:

  • Lea la calificación actual del restaurante y calcule la nueva
  • Agregar la calificación a la subcolección
  • Actualizar la calificación promedio del restaurante y el número de calificaciones

Abra RestaurantDetailActivity.java e implemente la función 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;
            }
        });
    }

La función addRating() devuelve una Task representa la transacción completa. En la función onRating() se agregan oyentes a la tarea para responder al resultado de la transacción.

Ahora ejecute la aplicación nuevamente y haga clic en uno de los restaurantes, que debería abrir la pantalla de detalles del restaurante. Haga clic en el botón + para comenzar a agregar una reseña. Agregue una reseña seleccionando varias estrellas e ingresando un texto.

78fa16cdf8ef435a.png

Al hacer clic en Enviar, se iniciará la transacción. Cuando se complete la transacción, verá su reseña a continuación y una actualización del recuento de reseñas del restaurante:

f9e670f40bd615b0.png

¡Felicitaciones! Ahora tiene una aplicación de revisión de restaurantes local, social y móvil construida en Cloud Firestore. Escuché que esos son muy populares en estos días.

Hasta ahora no hemos considerado la seguridad de esta aplicación. ¿Cómo sabemos que los usuarios solo pueden leer y escribir los datos propios correctos? Las bases de datos de Firestore están protegidas por un archivo de configuración llamado Reglas de seguridad .

Abra el archivo firestore.rules , debería ver lo siguiente:

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;
    }
  }
}

Cambio de dejar que estas reglas para evitar que los datos no deseados acesss o cambios, abra la firestore.rules archivo y reemplazar el contenido con lo siguiente:

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;
      }
    }
  }
}

Estas reglas restringen el acceso para garantizar que los clientes solo realicen cambios seguros. Por ejemplo, las actualizaciones de un documento de restaurante solo pueden cambiar las calificaciones, no el nombre o cualquier otro dato inmutable. Las calificaciones solo se pueden crear si el ID de usuario coincide con el usuario que inició sesión, lo que evita la suplantación de identidad.

Para leer más sobre las reglas de seguridad, visite la documentación .

Ahora ha creado una aplicación con todas las funciones en la parte superior de Firestore. Aprendió sobre las funciones más importantes de Firestore, que incluyen:

  • Documentos y colecciones
  • Leer y escribir datos
  • Ordenar y filtrar con consultas
  • Subcolecciones
  • Actas

Aprende más

Para seguir aprendiendo sobre Firestore, aquí hay algunos buenos lugares para comenzar:

La aplicación de restaurante en este codelab se basó en la aplicación de ejemplo "Friendly Eats". Puede buscar el código fuente de esa aplicación aquí .

Opcional: implementar en producción

Hasta ahora, esta aplicación solo ha utilizado Firebase Emulator Suite. Si desea aprender a implementar esta aplicación en un proyecto de Firebase real, continúe con el siguiente paso.

Hasta ahora, esta aplicación ha sido completamente local, todos los datos están contenidos en Firebase Emulator Suite. En esta sección, aprenderá a configurar su proyecto de Firebase para que esta aplicación funcione en producción.

Autenticación de Firebase

En la consola de Firebase, vaya a la sección Autenticación y navegue hasta la pestaña Proveedores de inicio de sesión .

Habilite el método de inicio de sesión por correo electrónico:

334ef7f6ff4da4ce.png

Firestore

Crear base de datos

Navegue a la sección Firestore de la consola y haga clic en Crear base de datos :

  1. Cuando se le pregunte acerca de las reglas de seguridad, elija comenzar en modo bloqueado , actualizaremos esas reglas pronto.
  2. Elija la ubicación de la base de datos que le gustaría usar para su aplicación. Tenga en cuenta que la selección de una ubicación de base de datos es una decisión permanente y para cambiarla tendrá que crear un nuevo proyecto. Para obtener más información sobre cómo elegir una ubicación para el proyecto, consulte la documentación .

Implementar reglas

Para implementar las reglas de seguridad que escribió anteriormente, ejecute el siguiente comando en el directorio de codelab:

$ firebase deploy --only firestore:rules

Esto implementará el contenido de firestore.rules en su proyecto, que puede confirmar navegando a la pestaña Reglas en la consola.

Implementar índices

La aplicación FriendlyEats tiene una clasificación y un filtrado complejos que requieren una serie de índices compuestos personalizados. Estos se pueden crear a mano en Firebase console, pero es más sencillo escribir sus definiciones en el archivo firestore.indexes.json e implementarlas mediante Firebase CLI.

Si abre el archivo firestore.indexes.json , verá que ya se han proporcionado los índices necesarios:

{
  "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": []
}

Para implementar estos índices, ejecute el siguiente comando:

$ firebase deploy --only firestore:indexes

Tenga en cuenta que la creación de índices no es instantánea, puede monitorear el progreso en Firebase console.

Configurar la aplicación

En la clase FirebaseUtil configuramos el SDK de Firebase para conectarse a los emuladores cuando está en modo de depuración:

public class FirebaseUtil {

    /** Use emulators only in debug builds **/
    private static final boolean sUseEmulators = BuildConfig.DEBUG;

    // ...
}

Si desea probar su aplicación con su proyecto de Firebase real, puede:

  1. Cree la aplicación en modo de lanzamiento y ejecútela en un dispositivo.
  2. Cambie temporalmente sUseEmulators a false y sUseEmulators a ejecutar la aplicación.

Tenga en cuenta que puede que tenga que cerrar la sesión de la aplicación y acceder de nuevo con el fin de conectar correctamente a la producción.