[mensaje-curso]
En los dos artículos anteriores (parte 2 y parte 3) de la serie, nos hemos ocupado de repasar las diferentes formas que tenemos disponibles para leer y mostrar los datos de nuestra base de datos de Firebase, ya sean datos concretos o listas de elementos. Sin embargo aún nos quedan un par de temas importantes que tratar sobre el acceso a los datos: el filtrado y la ordenación de la información. Ambos mecanismos deben ser tareas habituales para aquellas personas acostumbradas a trabajar con bases de datos SQL tradicionales, y en este artículo veremos cómo aplicarlos sobre los datos almacenados en una base de datos de Firebase.
Lo primero que debemos tener en cuenta es que en Firebase no vamos a tener todas las facilidades de ordenación y filtrado que suelen encontrarse en bases de datos SQL tradicionales. Por ejemplo, sólo podremos ordenar por un solo criterio, siempre ascendente, y que podrá basarse en la clave o el valor de los elementos de la lista, y adicionalmente el criterio de filtrado (si se utiliza) será dependiente del criterio de ordenación elegido. Así, si por ejemplo ordenamos una lista por el valor de sus elementos, si queremos utilizar algún criterio de filtrado éste se tendrá que basar también, necesariamente, en el valor de los elementos (no podría por ejemplo filtrar por la clave). Lo iremos entendiendo mejor a lo largo del artículo.
Empecemos por los diferentes métodos de ordenación disponibles. Firebase ofrece tres criterios de ordenación diferentes:
- orderByKey(). Ordena la información por la clave de cada elemento de la lista, en orden ascendente.
- orderByValue(). Ordena la información por el valor de cada elemento de la lista, en orden ascendente.
- orderByChild(). Ordena la información por el valor de una clave hija concreta de cada elemento de la lista, en orden ascendente.
La ordenación por clave (orderByKey) no necesita más explicación. En cuanto a las dos restantes, la ordenación directa por valor (orderByValue) tendrá más sentido cuando los elementos de la lista tengan un valor simple (numérico, alfanumérico o booleano), y la ordenación por el valor de una clave hija (orderByChild) nos será más útil cuando los elementos de la lista sean objetos, es decir, cuando contengan subelementos, y queramos ordenar por el valor de alguno de estos subelementos.
Veamos un par de ejemplos. Como ejemplo de lista con elementos simples recuperemos nuestra lista de días de la semana:
Si recuperamos esta lista ordenada por clave (orderByKey) obtendremos los elementos exactamente en el mismo orden que vemos en la imagen anterior, ya que en mi caso utilicé claves correlativas y ascendentes (aunque por supuesto esto no tiene por qué ser así necesariamente).
Si ordenamos la lista por valores (orderByValue) obtendríamos los elementos en este orden (por orden alfabético del campo valor):
- {dia4: «jueves»}
- {dia1: «lunes»}
- {dia2: «martes»}
- {dia3: «miercoles»}
- {dia6: «sábado»}
Para este ejemplo no tendría mucho sentido utilizar una ordenación por clave hija ya que los elementos de la lista no contienen subelementos. Pero podemos recuperar el ejemplo de las predicciones meteorológicas:
En este caso, podríamos ordenar la lista por el valor de cualquiera de las claves de los nodos hijo de cada elemento. Por ejemplo, si ordenamos por el campo «cielo» de cada elemento obtendríamos la lista en este orden:
- {20161122: {cielo: «Lluvia», …}}
- {20161121: {cielo: «Nublado», …}}
- {20161120: {cielo: «Soleado», …}}
Habiendo entendido los diferentes métodos de ordenación ya solo nos queda saber cómo aplicarlos al recuperar los datos de Firebase. Para ello, basta con utilizar el método correspondiente al crear la referencia a la base de datos, teniendo en cuenta además que el resultado ya no será un objeto de tipo DatabaseReference, sino de tipo Query (que realmente es una superclase de DatabaseReference).
Así, por ejemplo, para ordenar la lista de días de la semana por clave haríamos lo siguiente:
Query diasSemanaPorClave = FirebaseDatabase.getInstance().getReference() .child("dias-semana") .orderByKey();
Para obtenerla ordenada por valor se haría de forma análoga:
Query diasSemanaPorValor = FirebaseDatabase.getInstance().getReference() .child("dias-semana") .orderByValue();
Por último, para ordenar la lista de predicciones meteorológicas por la clave hija «cielo» de cada elemento, haríamos lo siguiente:
Query prediccionesPorClaveHija = FirebaseDatabase.getInstance().getReference() .child("predicciones") .orderByChild("cielo");
Como podéis comprobar es tan sencillo como pasar el nombre de la clave hija por la que queremos ordenar al método orderByChild().
Tras obtener una referencia de esta forma, el resto del trabajo con la base de datos se realiza exactamente igual a como lo hemos descrito en artículos anteriores, usando nuestro objeto Query en lugar de una referencia «normal» de tipo DatabaseReference.
Vamos ya con los métodos de filtrado o de consulta (query) en Firebase. Como hemos dicho anteriormente, el método de filtrado que apliquemos debe basarse necesariamente en el mismo campo por el que hayamos realizado la ordenación de la lista. Así, si ordenamos por clave, podremos filtrar por dicha clave. Si ordenamos por valor podremos filtrar por valor, y de forma análoga en el caso de ordenar por una clave hija.
Los distintos métodos de filtrado/consulta que tendremos disponibles serán los siguientes:
- limitToFirst(N). La consulta sólo devolverá los primeros N elementos de la lista ordenada.
- limitToLast(N). La consulta sólo devolverá los últimos N elementos de la lista ordenada.
- startAt(…). La consulta sólo devolverá los elementos cuya clave/valor/valor_clave_hija (según el método de ordenación elegido) sea igual o superior al dato pasado como parámetro.
- endAt(…). La consulta sólo devolverá los elementos cuya clave/valor/valor_clave_hija (según el método de ordenación elegido) sea igual o inferior al dato pasado como parámetro.
- equalTo(…). La consulta sólo devolverá los elementos cuya clave/valor/valor_clave_hija (según el método de ordenación elegido) sea igual al dato pasado como parámetro.
Al contrario de lo que ocurre con los métodos de ordenación, en este caso sí podremos utilizar varios criterios de filtrado en la misma consulta, es decir, podremos combinar varios de los métodos anteriores para obtener sólo el rango de elementos necesario. Así, si ordenamos por ejemplo por valor, podríamos recuperar los primeros 50 valores de la lista (limitToFirst(50)) que sean mayores a un determinado valor «X» (startAt(«X»)). Este tipo de filtros podrían servirnos por ejemplo para paginar una lista grande de elementos.
La forma de aplicar los criterios de filtrado es análoga a la de los métodos de ordenación, utilizando el/los métodos necesarios al crear la referencia a la base de datos. Así, por ejemplo, si volvemos a utilizar el ejemplo de los días de la semana, podríamos obtener los 2 días siguientes al «miércoles» (inclusive) de la siguiente forma:
Query diasSemanaPorValorFiltrado = FirebaseDatabase.getInstance().getReference() .child("dias-semana") .orderByValue() .startAt("miercoles") .limitToFirst(2);
Con este criterio obtendríamos la siguiente lista:
- {dia3: «miercoles»}
- {dia6: «sábado»}
Y en principio nada más sobre los criterios de ordenación y filtrado de Firebase. Ya solo nos quedaría volver sobre un detalle que dejamos pendiente en el artículo anterior. Cuando comentamos los eventos que podíamos gestionar al suscribirnos a una lista de elementos, dejamos apartado temporalmente el evento llamado onChildMoved(). Entonces no tenía mucho sentido que un elemento de una lista pudiera moverse de sitio, y por eso dejamos su explicación para más adelante. Ahora, una vez introducidos los criterios de ordenación y filtrado de Firebase, este evento cobra sentido de forma inmediata. El evento onChildMoved() se lanzará cada vez que un elemento de una lista ordenada cambie de posición debido a una modificación de su valor (lo que incluye a sus subelementos) y por tanto irá acompañado habitualmente del evento onChildChanged(). Todo esto nos permitirá ser notificados de este tipo de cambios en nuestra lista para actuar en consecuencia si fuera necesario, por ejemplo cambiando la posición del elemento en alguna lista que se esté mostrando al usuario en la interfaz de nuestra aplicación (si se usa FirebaseUI, como vimos en el artículo anterior, no será necesario preocuparnos de estos temas).
Con esto terminaríamos por el momento con las alternativas que ofrece Firebase para leer y consultar información de su base de datos. En el artículo siguiente comenzaremos ya a hablar de las distintas formas que tenemos disponibles para escribir y actualizar los datos desde nuestra aplicación Android.
Puedes consultar y/o descargar el código completo de los ejemplos desarrollados en este artículo accediendo a la página del curso en GitHub.
[mensaje-curso]
5 comentarios
[…] Base de datos Firebase en Android (4) [Diciembre 2016] […]
Hola. Muy buen trabajo.
Tengo una duda…En la estructura Database que yo tengo, uso un nodo principal (usuarios) que tiene hijos que son un id único que se genera al grabar datos con «push()». Éstos, a su vez, tienen hijos con los datos de cada usuario (nombre, mail, etc.). El problema que tengo es hacer una consulta discriminada por ese id que desde la aplicación Android desconozco, por lo que no puedo saber el «nombre» de ese hijo del nodo principal (usuarios). Evidentemente si entro en Firebase lo averiguo, pero desde Android no, o no he encontrado la forma de hacerlo.
En resumen…¿cómo realizo una consulta tipo «select…from…where»? Vengo de MySql y esto me ha pillado algo despistado. Espero haberme explicado bien.
Un saludo y Gracias.
Excelente artículo, simple , sencillo y al grano.
Como puedo hacer una consulta tipo inner join, necesito sacar el nombre de la tabla persona, guardo idpersona en otra tabla peros deseo mostrar el nombre el lugar del id. He visto info pero es en web y ocupo ejemplo en android agradeceria mucho si me ayudan
Tengo la misma pregunta que Ruben.
«Como puedo hacer una consulta tipo inner join, necesito sacar el nombre de la tabla persona, guardo idpersona en otra tabla peros deseo mostrar el nombre el lugar del id. He visto info pero es en web y ocupo ejemplo en android agradeceria mucho si me ayudan»