6

De SQL a Firebase Database

Al terminar de ver este curso, me quede pensando, ¿qué hay de las consultas (las que empezaban con SELECT *) de SQL?¿qué pasa si quiero filtrar los datos, si quiero hacer búsquedas, y todas las posibilidades que teníamos al trabajar con una base de datos MySQL o PostgreSQL?

Eso me llevo a buscar un poco en la web (gracias, ¡google!) y aquí comparto lo que encontré:

Las bases de datos SQL usan tablas para almacenar datos, esas tablas tienen columnas y filas donde se almacenan los datos.

Una columna es básicamente una propiedad de la tabla.

Por ejemplo, una tabla podría tener 3 columnas: ID, Nombre, Apellido.

Y las filas son los registros insertados, así que si las columnas son ID, NOMBRE y APELLIDO, entonces la primera fila en mi caso sería “ebrattJorge, Jorge, Vergara”.

Dónde:

  • ebrattJorge es mi identificación.

  • Jorge es mi primer nombre.

  • Vergara es mi apellido.

Si deseo agregar mi correo electrónico, no puedo simplemente enviarlo con el resto de los datos ebrattJorge, Jorge, Vergara, [email protected], esto no funcionarán, ya que la columna de correo electrónico no existe en nuestra tabla.

Tendría que modificar la tabla para aceptar el nuevo valor, esto también tiene sus ventajas, por ejemplo, es asegurarse de que la integridad de los datos permanezca en toda la base de datos.

Firebase (y, en su mayoría, todas las bases de datos NoSQL), por otro lado, no tienen este tipo de restricciones.

La base de datos de Firebase es solo un gran objeto JSON donde puedes almacenar lo que quieras dentro. A diferencia de SQL, no hay esquema para la base de datos, ni tablas, ni columnas, solo es una combinación de pares clave / valor.

Por ejemplo, nuestra tabla de usuarios en Firebase se vería así:

{
  users: {
    "ebrattJorge": {
      "first_name": "Jorge",
      "last_name": "Vergara",
      "email": "[email protected]"
    }
  }
}

Básicamente, se puede agregar cualquier información que se desee agregar al nodo del usuario. Esto es realmente bueno para la flexibilidad, pero no nos ayuda a garantizar la integridad de los datos. Entonces tomas lo bueno con lo malo.

En esta publicación, haré todo lo posible por guiarte en cómo estructurar tus datos en Firebase, para lograr lecturas ultrarrápidas, consultas mínimas y cómo hacer una consulta SQL común para reestructurar tus datos.

Lo dividiremos en 3 partes:

  • Mejores prácticas para la estructura de datos.
  • Un ejemplo práctico de quién estructurar los datos.
  • Una forma de garantizar la integridad de los datos al actualizar.

Mejores prácticas de Firebase

Una de las mejores maneras de garantizar que su aplicación siga siendo efectiva es mantener la conexión de la base de datos “limpia”, lo que significa que no hay demasiado desorden, demasiadas llamadas a la base de datos para cosas que realmente no necesita.

Con eso en mente, vayamos directamente a las mejores prácticas:

READ> WRITE
Debería pensar de manera predeterminada en cómo va a leer los datos que va a almacenar en la base de datos.

Estadísticamente hablando, el usuario promedio va a pasar más tiempo leyendo datos de la base de datos que escribiendo, por lo que querrá asegurarse de que leer los datos sea lo más sencillo posible y use la menor cantidad de recursos posible.

Por ejemplo, si está creando una aplicación de gestión de eventos (… que una vez tuve que hacer para mi esposa: P), podría estar pensando en cómo almacenar a los usuarios, los eventos que está creando y la relación entre ellos.

Usted podría estar pensando algo como esto:

{
  users: {
    "ebrattJorge": {
      "first_name": "Jorge",
      "last_name": "Vergara",
      "email": "[email protected]"
    }
  },
  events: {
    "natlPizzaDay": {
      "eventName": "National Pizza Day Celebration",
      "eventDate": "03/21/2017",
    }
  }
}

Y ese es un buen comienzo, pero ¿cómo relacionamos los asistentes al evento con el evento? Por ejemplo, supongamos que se debe enumerar a todos los que asistieron a la “Celebración del Día Nacional de la Pizza”.

Entonces puedes hacer algo como esto dentro del nodo de eventos:

events: {  
  "natlPizzaDay": {
    "eventName": "National Pizza Day Celebration",
    "eventDate": "03/21/2017",
    "guestList": {
      "ebrattJorge": true
    }
  }
}

Simplemente agregamos la identificación del usuario como clave con el valor igual a verdadero, por lo que sabemos que el usuario con la ID de “ebrattJorge” fue al evento

En realidad, este es un gran comienzo, pero si desea obtener más información sobre estos usuarios (y probablemente lo desee), deberá usar la identificación del usuario para consultar su información.

¿Cómo evitamos esa consulta adicional?

DE-Normalization
Si provienes de un fondo SQL, probablemente sepas acerca de la normalización (evitar duplicados, tablas de estructura, etc.). Firebase tiene un flujo diferente, y es DE-Normalization, donde en realidad está bien (de hecho, es una buena práctica) duplicar datos.

¿Cuantos datos puedo duplicar? ¿Honestamente? No tengo idea.

Depende de tu base de datos, tus objetivos, y especialmente en tu vista, por ejemplo:

Tienes una vista de evento, donde estás viendo la información sobre ese evento, dentro de la vista, tienes una lista de invitados, que muestra exactamente eso, una lista de los invitados que asistieron al evento.

Probablemente no vas a necesitar mucha información sobre los invitados en ese punto, así que en lugar de hacer una consulta adicional, podría hacer algo como esto:

events: {  
  "natlPizzaDay": {
    "eventName": "National Pizza Day Celebration",
    "eventDate": "03/21/2017",
    "guestList": {
      "ebrattJorge": {
        "first_name": "Jorge""last_name": "Vergara"
      }
    }
  }
}

De esta forma tendrás todos los datos que necesitas sobre los invitados, por lo que no tendrás que llamar a la base de datos por segunda vez para mostrar la lista de invitados.

Puedes ir un paso más allá y hacer lo mismo con las personas para que siempre tengas una lista de los eventos a los que ha asistido un usuario.

users: {  
  "ebrattJorge": {
    "first_name": "Jorge",
    "last_name": "Vergara",
    "email": "[email protected]",
    "events": {
      "natlPizzaDay": {
        "name": "National Pizza Day",
      }
    }
  }
}

Esta es una gran manera de comenzar a de-normalizar los datos, y para la mayoría de los casos de uso, puedes dejarlo así, pero si crees que tu aplicación será “grande”, entonces hay una trampa aquí.

Firebase usa referencias para extraer sus datos, por ejemplo, si desea realizar el evento “National Pizza Day”, hará algo como esto:

let eventRef = firebase.database().ref("events/natlPizzaDay");  

Eso traerá toda la información del evento, así que si todo lo que necesitas es el nombre del evento + fecha, entonces esta no es una gran idea, vas a extraer un montón más de datos de los que necesitas si esas listas internas comienzan a crecer.

Pero no te preocupes, hay una forma de evitar esto.

Manteniendo tus datos planos

Firebase admite anidamiento profundo (creo que hasta 32 niveles) para sus datos, pero es una mala idea ir tan profundo, imagina que solo se necesita el nombre del evento y, en su lugar, obtienes el nombre + una lista de 5.000 personas que asistieron al evento ( y el Día Nacional de la Pizza? como 5,000 millones de personas)

Si vienes de SQL, imagina esto como una relación “Muchos a muchos”, donde creas una tabla adicional para almacenar la relación.

Por ejemplo, volvamos a nuestra relación de evento / usuario, ¿qué ocurre si en lugar de almacenar GuestList dentro del nodo de evento creamos una tabla separada para él?

events: {  
  "natlPizzaDay": {
    "eventName": "National Pizza Day Celebration",
    "eventDate": "03/21/2017"
  }
},
eventGuestList: {  
  "natlPizzaDay": {
    "ebrattJorge": {
      "first_name": "Jorge""last_name": "Vergara"
    }
  }
}

De esta forma, si estás creando una página de detalles para el evento, puedes hacer 2 llamadas a Firebase independientes una de la otra:

let eventDetailRef = firebase.database().ref("events/natlPizzaDay");  
let eventGuestListRef = firebase.database().ref("eventGuestList/natlPizzaDay");  

Esas llamadas se realizarán de forma independiente y puede elegir dónde o cómo ejecutarlas / devolverlas. De esta forma, solo estás extrayendo los datos que necesitas de la base de datos. Al final, la estructura se vería así:

events: {  
  "natlPizzaDay": {
    "eventName": "National Pizza Day Celebration",
    "eventDate": "03/21/2017"
  }
},
eventGuestList: {  
  "natlPizzaDay": {
    "ebrattJorge": {
      "first_name": "Jorge""last_name": "Vergara"
    }
  }
},
users: {  
  "ebrattJorge": {
    "first_name": "Jorge",
    "last_name": "Vergara",
    "email": "[email protected]",
  }
}

Esto le da la mejor flexibilidad por mucho, pero hay un pequeño inconveniente (y por pequeño quiero decir realmente grande), ¿qué sucede si mi nombre está equivocado?

¿Qué pasa si necesitas actualizar el nombre de alguien? En SQL, esto es fácil porque simplemente actualizas el nombre del usuario y las modificaciones comienzan a aparecer mágicamente en toda su aplicación.

Si accedes a los usuarios / ebrattJorge / y cambias “first_name”: “Andres” no afectará nada más que ese nodo, lo que significa que terminarás con algo como esto:

eventGuestList: {  
  "natlPizzaDay": {
    "ebrattJorge": {
      "first_name": "Jorge"
    }
  }
},
users: {  
  "ebrattJorge": {
    "first_name": "Andres",
  }
}

Y eso es solo un gran NO, no puedes permitir que eso suceda, para eso puedes actualizar manualmente cualquier otra instancia donde esté el nombre del usuario (y de forma manual quiero decir que puedes crear una función para él), así sería algo como:

firebase.database().ref('users/ebrattJorge').update({  
  "name" : "Andres"
});

firebase.database().ref('eventGuestList/natlPizzaDay/ebrattJorge').update({  
  "name" : "Andres"
});

Está bien, supongo, el problema es que no tienes idea de cómo es la conexión a Internet del usuario, ¿qué sucede si tienes que actualizar el nombre en varios lugares y cuando la aplicación ha actualizado 2 nodos, hay un corte de energía?

Entonces tendrás algunos nodos actualizados y algunos desactualizados, lo que significa que se saltará manualmente (y esta vez sí quiero decir manualmente) a tu base de datos y uno por uno actualizando esos nombres.

Tu lo sabes, tu tiempo es demasiado valioso para eso.

Para esos casos, Firebase tiene una función genial, se llama actualizaciones de varias partes, básicamente es una función en la que encadenas cada actualización que necesitas y Firebase la trata como UNA operación de actualización.

Si se borran todas las actualizaciones, la función tendrá éxito, si falla en alguna parte a través de las actualizaciones, se revertirá y no cambiará nada, de esa manera podrá volver a intentarlo cuando se restablezca la conexión a Internet.

Esto es cuando tratamos de obtener un poco de la integridad de datos que ofrecen las bases de datos SQL 😃

Permítanme que les guie paso por paso de cómo ocurriría esta actualización en nuestro pequeño ejemplo:

Primero, necesitarías crear una referencia a su nodo raíz:

const rootRef = firebase.database().ref('/');  

Después de eso, crearemos un objeto para almacenar nuestras actualizaciones:

letupdatedUserName = {};  

Y luego comenzaremos a agregar las actualizaciones a ese objeto:

updatedUserName["users/ebrattJorge/first_name"] = "Andres";  
updatedUserName["eventGuestList/natlPizzaDay/ebrattJorge/first_name"] = "Andres";  

Y luego le diremos a nuestro rootRef que ejecute esas actualizaciones.

rootRef.update(updatedUserName, (error) => {  
  if(error){ console.log(error) }
});

Es una operación atómica (algo así como Git commits) por lo que actualizará todas las rutas o ninguna de ellas.

Próximos pasos

Y ahora?
Puedes seguir indagando sobre esto, y para eso te dejo algunos enlaces incluyendo este POST de su fuente. Aunque se recomienda altamente saber inglés 😉

Escribe tu comentario
+ 2
1
5615Puntos

Lo acabo de ver y muy buena explicacion, crei que pensar en no relacional y en firebase s eme hacia algo complicado, me acostumbre a relacionar, pero esta forma simple de separar tablas en listas, y crear listas secundarias no deberia dar miedo, ahora vere las referencias, seguire aprendiendo y experimentando, me ayudo bastante enserio muchas gracias.

1

Muy buena explicacion. Tengo una duda con respecto Al tipo de dato Reference en cloud firebase.