Estructurando Datos en Cloud Firestore

Adrián Ferrera González
CanariasJS
Published in
8 min readJun 16, 2018
Photo by Zbysiu Rodak on Unsplash

Cloud Firestore es uno de los tipos de base de datos NoSQL ofrecidos por Firebase para almacenar los datos de nuestras aplicaciones.

Cloud Firestore es una base de datos flexible y escalable para la programación en servidores, dispositivos móviles y la Web desde Firebase y Google Cloud Platform. Al igual que Firebase Realtime Database, mantiene tus datos sincronizados entre apps cliente a través de agentes de escucha en tiempo real y ofrece asistencia sin conexión para dispositivos móviles y la Web, por lo que puedes compilar apps con capacidad de respuesta que funcionan sin importar la latencia de la red ni la conectividad a Internet. Cloud Firestore también ofrece una integración sin interrupciones con otros productos de Firebase y Google Cloud Platform, incluido Cloud Functions.

Cabe destacar que a día de hoy, aún se encuentra en versión beta, pero resulta bastante robusta y no he encontrado prácticamente ningún problema en su uso con aplicaciones en producción.

Como en cualquier base de datos, es de vital importancia dedicar especial cariño a su diseño, ya que invertir el tiempo necesario en la correcta estructuración de los datos, podría llevarnos al éxito… o en su defecto a la más profunda frustración.

¿Qué nos permite Cloud Firestore?

Debemos recordar que se trata de una base de datos NoSQL, por lo que para quienes solemos trabajar con bases de datos orientas a documentos como puede ser MongoDB, ésta no nos pillará desprevenidos.

Como resumen se podría decir que la base de datos se estructura en colecciones, y que dichas colecciones contienen documentos (que son el conjunto de atributos y valores que definen un objeto). Cada colección tiene su nombre, mientras que cada documento tiene su identificador único.

Ejemplo de estructura de datos

Recordemos que los documentos de una colección no tienen por qué tener los mismos atributos que sus hermanos.

Como comentamos previamente, Cloud Firestore se trata de una de las herramientas ofrecidas por Google en el servicio de Firebase, por lo que en primera instancia debemos estar dados de alta en el servicio. Para ello basta con acceder a la url y autenticarse con la cuenta de Google.

https://console.firebase.google.com/

Pantalla de inicio de Firebase

Una vez hecho esto, podremos crear un proyecto Firebase, o acceder a uno ya existente.

En el caso de crear un nuevo proyecto, se nos preguntará el nombre que deseamos darle y la región donde se encontrará hospedado el servicio. Esta última es de especial relevancia de cara a la RGPD (Reglamento General de Protección de Datos).

Creación del Proyecto Firebase

Cuando cumplimentamos la información indicada, se procederá a la creación del proyecto.

Dashboard por defecto de Firebase
Selección de base de datos a utilizar

Una vez termine el proceso, nos redireccionarán al dashboard de Firebase, donde tendremos acceso a todos los servicios del proyecto.

Para acceder finalmente a Firestore, deberemos dirigirnos al apartado Database e indicar que queremos acceder a Cloud Firestore.

Nos preguntarán el nivel de seguridad que queremos definir, elegiremos por defecto la primera opción, definida como “modo bloqueado”, la cual restringe el acceso a los datos a cualquier persona y solo podrán ser editados desde el panel de Firestore. Este valor podrá ser modificado posteriormente por la segunda opción “modo de prueba”.

Configuración de reglas por seguridad por defecto

Una vez en Cloud Firestore

Cuando accedemos a Cloud Firestore, veremos el concepto de Colección plasmado anteriormente, mostrado de la siguiente manera:

Cloud Firestore vacío

Existen diferentes secciones: Datos, Reglas, Índice y Uso. En este artículo nos centraremos en las dos primeras, dejando las otras para ser tratadas en futuras publicaciones.

Como ya nos adelanta la interfaz, nuestra base de datos se dividirá en colecciones (1), las cuales se encargarán de almacenar nuestros documentos (2).

Cada documento (2) tendrá a su vez un identificador único que puede ser autogenerado o fijado según nuestro propio criterio.

Organización de la herramienta

Y dentro del documento podremos definir un conjunto de campos (3), que viene a ser la propia información del documento, o incluso un conjunto de colecciones específicas de ese documento. (Quizás suena complejo pero lo trataremos en breve).

Ejemplo de colección y documento

De tal forma, si se consumiese el servicio usando /usuarios se nos devolvería un listado de un único documento, mientras que si se usase /usuarios/0NCBIu3TSntAyRksVO44/ se devolvería ese documento en concreto.

¿Qué son Subcolecciones y cuándo usarlas?

Como dejamos entrever antes, se pueden crear colecciones dentro de documentos. Estas colecciones son específicas de dicho documento y solo estarán accesibles a través de su ID.

Con esto quiero dejar claro que si se consulta el documento, tal y como se indicó antes (/usuarios/0NCBIu3TSntAyRksVO44/), no se devolverá la subcolección, sino el documento en si.

Para poder acceder a una subcolección en concreto, debemos consultarla específicamente:

/usuarios/ONCBIu3TSntAyRksVO44/[nombre de la colección]

Sin embargo…

¿Qué nos aporta esta función, que no nos aporte un campo Objeto dentro del documento?

Debemos plantearnos que en este tipo de base de datos, los permisos se gestionan a través de la URL que se consume, por lo que alguien que tiene permiso para acceder a /usuarios/0NCBIu3TSntAyRksVO44/ podría ver toda la información de dicho documento.

Al extraerlo a una colección dentro del documento, podremos segurizar dicha información de forma que, por ejemplo, sólo pueda acceder el propio usuario.

Reglas

Las reglas son sin duda uno de los apartados con mayor flexibilidad a la hora de configurar nuestra base de datos. Con ellas podremos definir los permisos a las distintas rutas en las que se expondrá la información almacenada.

Debemos recordar que la base de datos es expuesta a través de un formato REST basado en rutas, por lo que podremos definir que determinados usuarios puedan acceder a unas rutas específicas (o lo que es lo mismo, a datos específicos), pero no a otras.

Por defecto la configuración inicial de Firestore es la siguiente:

Esto nos quiere decir que toda ruta que coincida con:

/databases/{database}/documents

para cualquier documento que contenga:

/{document=**}

se le deniegue la lectura y la escritura:

allow read, write: if false

Si por el contrario quisiéramos permitir la escritura a cualquier usuario, bastaría con cambiar la condición final de if false, por if true, o eliminarla directamente.

Los términos clásicos que se manejarán en las reglas son:

  • Reglas: Permitir X acción.
  • Reglas: Denegar X acción.

Mientras que por otro lado tendremos las acciones:

  • create: Acción de crear.
  • read: Acción de leer.
  • update: Acción de actualizar.
  • delete: Acción de eliminar.

No obstante, podemos encontrar mayor información al respecto en la documentación oficial:

https://firebase.google.com/docs/firestore/security/get-started?hl=es-419

Reglas avanzadas

Sin embargo, esto no es todo lo que podemos gestionar con respecto a las reglas. Recordemos que, se trata de un objeto JavaScript, por lo que podemos implementar funciones más complejas.

Para ello vamos a presuponer que hemos configurado una colección de usuarios en nuestro esquema con la siguiente estructura:

Ejemplo de esquema usuarios

Como se observa, dentro de la colección users, existen múltiples documentos, los cuales constan de un atributo roles. Roles consiste en un objeto que contempla los distintos permisos que se quieran otorgar al usuario mediante un boolean:

Roles del usuario

Llegados a este punto, retomaremos la vista de Reglas. Vamos a implementar la lógica para que:

  • El rol subscriber únicamente pueda leer (read).
  • El rol editor pueda actualizar (update) documentos.
  • El rol admin sea el único en poder crear y eliminar (create, delete) documentos.

Antes de nada, debemos entender que las solicitudes que se realizan van contenidas en un objeto request, el cual contiene la información de la misma, entre las cuales estará el uid del usuario.

En primera instancia crearemos una función en javascript que nos devuelva si el usuario tiene un rol determinado. Para ello, buscaremos en la collección usuarios, el documento con el uidcontenido en la request.

A continuación pasaremos como parámetro el role, y lo buscaremos en la propiedad roles del mismo.

Ahora bien, esto nos devolverá true o false, en función de si el usuario que realiza la request, tiene ese permiso. Para realizar la restricción indicada podríamos concluir diciendo entonces que:

Dentro de la base de datos en cuestión, en la colección de /exercise:

  • Se permite la lectura si el rol es subscriber.
  • Se permite la actualización si el rol es editor.
  • Se permite la creación y el borrado si es admin.

Por último añadiremos un extra, indicando que el usuario deberá estar autenticado:

Quedando así nuestra configuración de rutas:

Conclusión

Podemos afirmar que Cloud Firestore es una base de datos extremadamente potente, con una considerable limpieza con respecto a configuración y estructura, que puede agilizar muchísimo los desarrollos de aplicaciones simples.

Espero que este artículo te haya servido de ayuda para comprender como se estructura y gestiona este servicio de base de datos. Si ha sido así, no dudes en darle un voto positivo y compartirlo en tus redes sociales para llegar a más gente. En futuras publicaciones abordaré cómo consumir este servicio a través de clientes web, y como gestionar los datos a través de patrones de estado.

Para estar al tanto de mis publicaciones, puedes encontrarme en mis redes sociales de Twitter y LinkedIn:

También me gustaría dar las gracias a Dailos Rafael Díaz Lara, por su gran ayuda en la elaboración y revisión de este artículo, el cual me ha ayudado a mejorar la calidad de toda la información expuesta. Podéis encontrarlo en:

--

--