Comenzando Con Cloud Firestore para Android
Spanish (Español) translation by Rafael Chavarría (you can also view the original English article)
Cloud Firestore es una adición reciente a la familia de productos Firebase. Aunque aún está en beta, ya está siendo presentado por Google como una alternativa más flexible y rica en características a la Base de Datos en Tiempo Real Firebase.
Si alguna vez has usado la Base de Datos en Tiempo Real, probablemente sabes que es esencialmente un documento JSON grande más útil para almacenar solamente pares de llave-valor simples. Almacenar datos jerárquicos en esta de manera eficiente y segura, aunque es posible, es bastante complicado y requiere una estrategia bien pensada, la cual usualmente involucra aplanar los datos tanto como sea posible o desnormalizarla. Con tal estrategia, las consultas en la Base de Datos en Tiempo Real son propensas a consumir cantidades de ancho de banda innecesariamente grandes.
Cloud Firestore, siendo más parecido a bases de datos orientadas a documentos tales como MongoDB y CouchDB, no tiene tales problemas. Lo que es más, viene con una gran cantidad de características muy útiles, como soporte para operaciones en lote, escrituras atómicas y consultas indexadas.
En este tutorial, te ayudaré a comenzar a usar Cloud Firestore en la plataforma Android.
Prerrequisitos
Para poder seguir este tutorial, necesitarás:
- la última versión de Android Studio
- una cuenta Firebase
- un dispositivo o emulador ejecutando Android 4.4 o superior
1. Creando un Proyecto Firebase
Antes de que uses productos Firebase en tu aplicación Android, debes crear un nuevo proyecto para esta en la consola Firebase. Para hacerlo, inicia sesión en la consola y presiona el botón Agregar Proyecto en la pantalla de bienvenida.



En el diálogo que aparece, dale un nombre significativo al proyecto, de manera opcional dale un ID significativo, y presiona el botón Crear Proyecto.



Una vez que el proyecto ha sido creado, puedes establecer Firebase como su base de datos navegando a Desarrollo > Base de Datos y presionando el botón Probar Firebase Beta.



En la siguiente pantalla, asegúrate de elegir la opción Comenzar en modo de prueba y presiona el botón Habilitar.



En este punto, tendrás una base de datos Firestore vacía lista para ser usada en tu aplicación.



2. Configurando el Proyecto Android
Tu proyecto Android Studio aún no sabe nada sobre el proyecto Firebase que creaste en el paso anterior. La manera más sencilla de establecer una conexión entre los dos es usar el Asistente Firebase de Android Studio.
Ve a Herramientas > Firebase para abrir el Asistente.



Debido a que Firestore aún está en beta, el Asistente no lo soporta aún. Aun así, agregando Firebase Analytics a tu aplicación, podrás automatizar la mayoría de los pasos requeridos de configuración.
Comienza dando clic en el enlace Registrar un Evento de Analítica bajo la sección de Analítica y presionando el botón Conectar a Firebase. Una nueva ventana de navegador debería aparecer preguntándote si quieres permitir que Android Studio, entre otras cosas, administre datos Firebase.



Presiona Permitir para continuar.
De vuelta en Android Studio, en el diálogo que aparece, selecciona la opción Elegir un proyecto Firebase o Google existente, selecciona el proyecto Firebase que creaste antes, y presiona el botón Conectar a Firebase.



Después, presiona el botón Agregar Analíticas a tu aplicación para agregar las dependencias Firebase principales a tu proyecto.
Finalmente, para agregar Firestore como una dependencia implementation,
agrega la siguiente línea en el archivo build.gradle del módulo app.
1 |
implementation 'com.google.firebase:firebase-firestore:11.8.0' |
No olvides presionar el botón Sincronizar Ahora para completar la configuración. Si encuentras cualquier error de conflicto de versión durante el proceso de sincronización, asegúrate de que las versiones de la dependencia Firestore y la dependencia Firebase Core sean idénticas y prueba de nuevo.
3. Entendiendo Documentos y Colecciones
Firestore es una base de datos NoSQL que te permite
almacenar datos en la forma de documentos como JSON. Sin embargo, un documento
almacenado en esta no puede existir de manera independiente. Siempre debe pertenecer a una colección. Como su nombre
sugiere, una colección no es más que un montón de documentos.
Los documentos dentro de una colección son obviamente
hermanos. Si quieres establecer relaciones padre-hijo entre ellos, debes usar
sub-colecciones. Una sub-colección es solo una colección que pertenece a un
documento. Por defecto, un documento se vuelve automáticamente el padre de
todos los documentos que pertenecen a sus sub-colecciones.
También vale la pena notar que Firestore administra la creación y borrado de ambas colecciones y sub-colecciones por sí misma. Siempre que intentas agregar un documento a una colección no existente, esta crea la colección. De manera similar, una vez que borras todos los documentos de una colección, esta la borra.
4. Creando Documentos
Para poder escribir la base de datos Firestore desde tu
aplicación Android, debes primero obtener la referencia a esta llamando el método
getInstance() de la clase FirebaseFirestore.
1 |
val myDB = FirebaseFirestore.getInstance() |
Después, debes ya sea crear una nueva colección y obtener
una referencia a una colección existente, llamando el método collection(). Por
ejemplo, en una base de datos vacía, el siguiente código crea una nueva
colección llamada solar_system:
1 |
val solarSystem = myDB.collection("solar_system") |
Una vez que tienes una referencia a una colección, puedes
comenzar a agregar documentos a esta llamando su método add(), el cual espera
un mapa como su argumento.
1 |
// Add a document
|
2 |
solarSystem.add(mapOf( |
3 |
"name" to "Mercury", |
4 |
"number" to 1, |
5 |
"gravity" to 3.7 |
6 |
))
|
7 |
|
8 |
// Add another document
|
9 |
solarSystem.add(mapOf( |
10 |
"name" to "Venus", |
11 |
"number" to 2, |
12 |
"gravity" to 8.87 |
13 |
))
|
El método add() genera y asigna de forma automática un identificador
alfanumérico único a todos los documentos que crea. Si quieres que tus
documentos tengan tus propios IDs personalizados, primero debes crear de manera
manual esos documentos llamando al método document(), el cuál toma una cadena
ID única como su entrada. Después puedes poblar el comento llamando al método set(),
el cual, como el método add, espera un
mapa como su único argumento.
Por ejemplo, el siguiente código crea y puebla un nuevo
documento llamado PLANET_EARTH:
1 |
solarSystem.document("PLANET_EARTH") |
2 |
.set(mapOf( |
3 |
"name" to "Earth", |
4 |
"number" to 3, |
5 |
"gravity" to 9.807 |
6 |
))
|
Si vas a la consola Firebase y echas un vistazo a los contenidos de la base de datos, podrás detectar el ID personalizado fácilmente.



Ten en cuenta que si el ID personalizado que pasas al método
document() ya existe en la base de datos, el método set() sobreescribirá el
documento asociado.
5. Creando Sub-colecciones
El soporte para sub-colecciones es una de las
características más poderosas de Firestore y es lo que lo hace marcadamente
diferente de la Base de Datos en Tiempo Real Firebase. Usando sub-colecciones,
no solo puedes agregar fácilmente estructuras anidadas a tus datos sino que
también puedes estar seguro de que tus consultas consumirán cantidades mínimas
de ancho de banda.
Crear una sub-colección es como crear una colección. Todo lo
que necesitas hacer es llamar al método collection() en un objeto
DocumentReference y pasarle una cadena, que será usada como el nombre de la
sub-colección.
Por ejemplo, el siguiente código crea una sub-colección
llamada satellites y la asocia con el documento PLANET_EARTH:
1 |
val satellitesOfEarth = solarSystem.document("PLANET_EARTH") |
2 |
.collection("satellites") |
Una vez que tienes una referencia a una sub-colección, eres
libre de llamar a los métodos add() o set() para agregar documentos a esta.
1 |
satellitesOfEarth.add(mapOf( |
2 |
"name" to "The Moon", |
3 |
"gravity" to 1.62, |
4 |
"radius" to 1738 |
5 |
))
|
Después de que ejecutas el código de arriba, el documento
PLANET_EARTH lucirá como esto en la consola Firebase:



6. Ejecutando Consultas
Realizar una operación de lectura en tu base de datos
Firestore es muy sencillo si conoces el ID del documento que quieres leer. ¿Por
qué? Debido a que puedes obtener una referencia directamente al
documento llamando a los métodos collection() y document(). Por ejemplo, aquí
está cómo puedes obtener una referencia al documento PLANET_EARTH que pertenece
a la colección solar_system:
1 |
val planetEarthDoc = myDB.collection("solar_system") |
2 |
.document("PLANET_EARTH") |
Para realmente leer los contenidos del documento, debes
llamar al método asíncrono get(), el cuál devuelve un Task. Agregando un
OnSuccessListener a este, puedes ser notificado cuando la operación de lectura
se complete de manera satisfactoria.
El resultado de la operación de lectura es un objeto
DocumentSnapshot, el cual contiene pares llave-valor presentes en el documento.
Usando su método get(), puedes obtener el valor de cualquier llave válida. El
siguiente ejemplo te muestra cómo:
1 |
planetEarthDoc.get().addOnSuccessListener { |
2 |
println( |
3 |
"Gravity of ${it.get("name")} is ${it.get("gravity")} m/s/s" |
4 |
)
|
5 |
}
|
6 |
|
7 |
// OUTPUT:
|
8 |
// Gravity of Earth is 9.807 m/s/s
|
Si no conoces el ID del documento que quieres leer, tendrás
que ejecutar una consulta tradicional sobre una colección entera. La API
Firestore proporciona métodos filtro nombrados de forma intuitiva tales como whereEqualTo(),
whereLessThan(), y whereGreaterThan(). Debido a que los métodos filtro pueden devolver múltiples
documentos como sus resultados, necesitarás un ciclo dentro de tu
OnSuccessListener para manejar cada resultado.
Por ejemplo, para obtener los contenidos del documento para el planeta Venus, el cuál agregamos en un paso anterior, podrías usar el siguiente código:
1 |
myDB.collection("solar_system") |
2 |
.whereEqualTo("name", "Venus") |
3 |
.get().addOnSuccessListener { |
4 |
it.forEach { |
5 |
println( |
6 |
"Gravity of ${it.get("name")} is ${it.get("gravity")} m/s/s" |
7 |
)
|
8 |
}
|
9 |
}
|
10 |
|
11 |
// OUTPUT:
|
12 |
// Gravity of Venus is 8.87 m/s/s
|
Por último, si estás interesado en leer todos los documentos
que pertenecen a una colección, puedes llamar directamente al método get()
sobre la colección. Por ejemplo, aquí está cómo puedes listar todos los
planetas presentes en la colección solar_system:
1 |
myDB.collection("solar_system") |
2 |
.get().addOnSuccessListener { |
3 |
it.forEach { |
4 |
println(it.get("name")) |
5 |
}
|
6 |
}
|
7 |
|
8 |
// OUTPUT:
|
9 |
// Earth
|
10 |
// Venus
|
11 |
// Mercury
|
Nota que, por defecto, no hay orden definitivo en el cual
los resultados son devueltos. Si quieres ordenarlos basados en una llave que está presente
en todos los resultados, puedes hacer uso del método orderBy(). El siguiente
código ordena los resultados basado en el valor del number de la llave:
1 |
myDB.collection("solar_system") |
2 |
.orderBy("number") |
3 |
.get().addOnSuccessListener { |
4 |
it.forEach { |
5 |
println(it.get("name")) |
6 |
}
|
7 |
}
|
8 |
|
9 |
// OUTPUT:
|
10 |
// Mercury
|
11 |
// Venus
|
12 |
// Earth
|
7. Borrando Datos
Para borrar un documento con un ID conocido, todo lo que
necesitas hacer es obtener una referencia a este y después llamar al método
delete().
1 |
myDB.collection("solar_system") |
2 |
.document("PLANET_EARTH") |
3 |
.delete() |
Borrar múltiples documentos----documentos que obtienes como el resultado de una consulta---es ligeramente más complicado porque no hay un método integrado para hacerlo. Hay dos aproximaciones diferentes que puedes seguir.
La más aproximación más sencilla e intuitiva---aunque solo
es útil para un número muy pequeño de documentos---es ciclar a través de los
resultados, obtener una referencia a cada documento, y después llamar al método
delete(). Aquí está cómo puedes usar la aproximación para borrar todos los
documentos en la colección solar_system:
1 |
myDB.collection("solar_system") |
2 |
.get().addOnSuccessListener { |
3 |
it.forEach { |
4 |
it.reference.delete() |
5 |
}
|
6 |
}
|
Una aproximación más eficiente y escalable es usar una operación en lote. Las operaciones en lote no solo pueden borrar múltiples documentos de manera automática sino que también reduce significativamente el número de conexiones de red requeridas.
Para crear un nuevo lote, debes llamar al método batch() de
tu base de datos, el cuál devuelve una instancia de la clase WriteBatch. Después, puedes ciclar a través de los resultados de la
consulta y marcarlos para borrado pasándoles el método delete() del objeto
WriteBatch. Finalmente, para comenzar realmente el proceso de borrado,
puedes llamar al método commit(). El siguiente código te muestra como:
1 |
myDB.collection("solar_system") |
2 |
.get().addOnSuccessListener { |
3 |
|
4 |
// Create batch
|
5 |
val myBatch = myDB.batch() |
6 |
|
7 |
// Add documents to batch
|
8 |
it.forEach { |
9 |
myBatch.delete(it.reference) |
10 |
}
|
11 |
|
12 |
// Run batch
|
13 |
myBatch.commit() |
14 |
}
|
Nota que intentar agregar demasiados documentos a una sola operación de lote puede llevar a errores de insuficiencia de memoria. De ahí que su tu consulta probablemente devuelva un gran número de documentos, debes asegurar que los partes en múltiples lotes.
Conclusión
En este tutorial de introducción, aprendiste cómo realizar operaciones de lectura y escritura en Google Cloud Firestore. Sugiero que comiences a utilizarlo en tus proyectos Android de inmediato. Hay una buena posibilidad de que reemplace a la Base de Datos en Tiempo Real en el futuro. De hecho, Google dice que cuando salga de beta, será mucho más confiable y escalable que la Base de Datos en Tiempo Real.
Para aprender más sobre Cloud Firestore, puedes referirte a su documentación oficial.
Y mientras estás aquí, ¡revisa algunos de nuestros otros tutoriales sobre Firebase y desarrollo de aplicaciones Android!


Android SDKCómo Crear una Aplicación de Chat Android Usando FIrebaseAshraff Hathibelagal

Android SDKComienza Con Firebase para AndroidAshraff Hathibelagal

Desarrollo MóvilReglas de Seguridad FirebaseChike Mgbemena

Android SDKCómo Subir Imágenes a Firebase desde una Aplicación AndroidChinedu Izuchukwu



