Trabaja con listas de datos en la Web

Obtén una referencia a una base de datos

Para leer o escribir en la base de datos, necesitas una instancia de firebase.database.Reference:

Web

import { getDatabase } from "firebase/database";

const database = getDatabase();

Web

var database = firebase.database();

Lectura y escritura de listas

Agrega datos a una lista de datos

Usa el método push() para agregar datos a una lista en aplicaciones multiusuario. Cada vez que se agrega un elemento secundario nuevo a la referencia de Firebase especificada, el método push() genera una clave única. Cuando se usan estas claves generadas automáticamente para cada elemento nuevo de la lista, varios clientes pueden agregar elementos secundarios a la misma ubicación al mismo tiempo sin conflictos de escritura. La clave única que genera push() se basa en una marca de tiempo. Por lo tanto, los elementos de las listas se ordenan cronológicamente de forma automática.

Puedes usar la referencia a los datos nuevos que muestra el método push() para obtener el valor de la clave generada automáticamente del elemento secundario o configurar los datos de dicho elemento. La propiedad .key de una referencia push() contiene la clave que se generó automáticamente.

Puedes usar estas claves generadas de manera automática para simplificar la compactación de tu estructura de datos. Para obtener más información, consulta el ejemplo de fan-out de datos.

Por ejemplo, push() podría usarse para agregar una entrada nueva a una lista de publicaciones en una aplicación social:

Web

import { getDatabase, ref, push, set } from "firebase/database";

// Create a new post reference with an auto-generated id
const db = getDatabase();
const postListRef = ref(db, 'posts');
const newPostRef = push(postListRef);
set(newPostRef, {
    // ...
});

Web

// Create a new post reference with an auto-generated id
var postListRef = firebase.database().ref('posts');
var newPostRef = postListRef.push();
newPostRef.set({
    // ...
});

Detecta eventos secundarios

Los eventos secundarios se activan en respuesta a operaciones específicas que se ejecutan en los elementos secundarios de un nodo a partir de una operación, como un elemento secundario nuevo que se agrega a través del método push() o un elemento secundario que se actualiza a través del método update().

Evento Uso común
child_added Recupera listas de elementos o detecta elementos agregados a una lista. Este evento se activa una vez por cada elemento secundario existente y otra vez cuando se agrega un elemento secundario nuevo a la ruta de acceso especificada. El agente de escucha recibe una instantánea que contiene los datos del nuevo elemento secundario.
child_changed Detecta cambios en los elementos de una lista. Este evento se activa cuando se modifica un nodo secundario. Esto incluye cualquier modificación en los descendientes del nodo secundario. La instantánea que se pasa al objeto de escucha de eventos contiene los datos actualizados del elemento secundario.
child_removed Detecta cuando se quitan elementos de una lista. Este evento se activa cuando se quita un elemento secundario inmediato. El resumen que se pasa al bloque de devolución de llamada contiene los datos del elemento secundario que se quitó.
child_moved Detecta cambios en el orden de los elementos de una lista ordenada. Los eventos child_moved siempre siguen al evento child_changed que generó el cambio en el orden de los elementos (en función del método de ordenamiento actual).

Cada uno de estos, en combinación, puede ser útil para detectar cambios en un nodo específico de una base de datos. Por ejemplo, una app social de blogs podría usar estos métodos en combinación para supervisar la actividad en los comentarios de una publicación, como se muestra a continuación:

Web

import { getDatabase, ref, onChildAdded, onChildChanged, onChildRemoved } from "firebase/database";

const db = getDatabase();
const commentsRef = ref(db, 'post-comments/' + postId);
onChildAdded(commentsRef, (data) => {
  addCommentElement(postElement, data.key, data.val().text, data.val().author);
});

onChildChanged(commentsRef, (data) => {
  setCommentValues(postElement, data.key, data.val().text, data.val().author);
});

onChildRemoved(commentsRef, (data) => {
  deleteComment(postElement, data.key);
});

Web

var commentsRef = firebase.database().ref('post-comments/' + postId);
commentsRef.on('child_added', (data) => {
  addCommentElement(postElement, data.key, data.val().text, data.val().author);
});

commentsRef.on('child_changed', (data) => {
  setCommentValues(postElement, data.key, data.val().text, data.val().author);
});

commentsRef.on('child_removed', (data) => {
  deleteComment(postElement, data.key);
});

Detecta eventos de valores

Si bien escuchar para detectar eventos secundarios es la manera recomendada de leer listas de datos, existen situaciones en las que escuchar para detectar eventos de valores en una referencia de lista puede ser útil.

Si agregas un observador de value a una lista de datos, se mostrará una lista completa de los datos en forma de una sola instantánea. Si le aplicas un bucle a ese resultado, puedes acceder a cada elemento secundario.

Incluso cuando hay una sola coincidencia para la búsqueda, la instantánea es una lista, aunque contenga un solo elemento. Para acceder al elemento, debes aplicar un bucle al resultado:

Web

import { getDatabase, ref, onValue } from "firebase/database";

const db = getDatabase();
const dbRef = ref(db, '/a/b/c');

onValue(dbRef, (snapshot) => {
  snapshot.forEach((childSnapshot) => {
    const childKey = childSnapshot.key;
    const childData = childSnapshot.val();
    // ...
  });
}, {
  onlyOnce: true
});

Web

ref.once('value', (snapshot) => {
  snapshot.forEach((childSnapshot) => {
    var childKey = childSnapshot.key;
    var childData = childSnapshot.val();
    // ...
  });
});

Este patrón puede ser útil cuando quieres recuperar todos los elementos secundarios de una lista en una sola operación, en lugar de escuchar para detectar cada evento secundario que se agrega.

Cómo ordenar y filtrar datos

Puedes usar la clase Query de Realtime Database para recuperar los datos organizados por clave, por valor o por valor del elemento secundario. También puedes filtrar el resultado ordenado de acuerdo con una cantidad específica de resultados o un rango de claves o valores.

Ordena los datos

Para recuperar datos ordenados, comienza por especificar uno de los métodos de ordenamiento, a fin de determinar cómo se presentarán los resultados:

Método Uso
orderByChild() Ordena los resultados según el valor de una clave secundaria especificada o una ruta de acceso secundaria anidada.
orderByKey() Ordena los resultados según las claves secundarias.
orderByValue() Ordena los resultados según los valores secundarios.

Puedes usar solo un método de ordenamiento a la vez. Si llamas a un método de ordenamiento varias veces en la misma consulta, se genera un error.

El siguiente ejemplo demuestra cómo podrías recuperar una lista de las principales publicaciones de un usuario según la cantidad de estrellas que tienen:

Web

import { getDatabase, ref, query, orderByChild } from "firebase/database";
import { getAuth } from "firebase/auth";

const db = getDatabase();
const auth = getAuth();

const myUserId = auth.currentUser.uid;
const topUserPostsRef = query(ref(db, 'user-posts/' + myUserId), orderByChild('starCount'));

Web

var myUserId = firebase.auth().currentUser.uid;
var topUserPostsRef = firebase.database().ref('user-posts/' + myUserId).orderByChild('starCount');

Esto define una búsqueda que, cuando se combina con un objeto de escucha de elementos secundarios, sincroniza el cliente con las publicaciones del usuario en la ruta de la base de datos según su ID de usuario, ordenadas según la cantidad de estrellas que recibió cada publicación. Esta técnica de usar IDs como claves de índice se denomina “fan-out de datos”. Puedes obtener más información al respecto en Estructura tu base de datos.

La llamada al método orderByChild() especifica la clave secundaria según la que se deben ordenar los resultados. En este caso, las publicaciones se ordenan según el valor del elemento secundario "starCount" respectivo. Las búsquedas también se pueden ordenar por campos secundarios anidados si tienes datos con la estructura siguiente:

"posts": {
  "ts-functions": {
    "metrics": {
      "views" : 1200000,
      "likes" : 251000,
      "shares": 1200,
    },
    "title" : "Why you should use TypeScript for writing Cloud Functions",
    "author": "Doug",
  },
  "android-arch-3": {
    "metrics": {
      "views" : 900000,
      "likes" : 117000,
      "shares": 144,
    },
    "title" : "Using Android Architecture Components with Firebase Realtime Database (Part 3)",
    "author": "Doug",
  }
},

En este caso, podemos ordenar nuestros elementos de lista por valores anidados en la clave metrics si especificamos la ruta de acceso relativa al elemento secundario anidado en nuestra llamada orderByChild().

Web

import { getDatabase, ref, query, orderByChild } from "firebase/database";

const db = getDatabase();
const mostViewedPosts = query(ref(db, 'posts'), orderByChild('metrics/views'));

Web

var mostViewedPosts = firebase.database().ref('posts').orderByChild('metrics/views');

Para obtener más información sobre cómo se ordenan otros tipos de datos, consulta la sección Cómo se ordenan los datos de las consultas.

Cómo filtrar datos

Para filtrar datos, puedes combinar cualquiera de los métodos de límite o rango con un método de ordenamiento cuando generes una consulta.

Método Uso
limitToFirst() Configura la cantidad máxima de elementos que pueden mostrarse desde el comienzo de la lista de resultados ordenada.
limitToLast() Configura la cantidad máxima de elementos que pueden mostrarse desde el final de la lista de resultados ordenada.
startAt() Muestra elementos con un valor mayor o igual que la clave o el valor que se especifica según el método de ordenamiento seleccionado.
startAfter() Muestra elementos con un valor mayor que la clave o el valor que se especificó según el método de ordenamiento seleccionado.
endAt() Muestra elementos con un valor menor o igual que la clave o el valor que se especifica según el método de ordenamiento seleccionado.
endBefore() Muestra elementos con un valor inferior a la clave o el valor que se especificó según el método de ordenamiento seleccionado.
equalTo() Muestra elementos con un valor igual a la clave o el valor que se especifica según el método de ordenamiento seleccionado.

A diferencia de los métodos de ordenamiento, las funciones de límite o rango pueden combinarse. Por ejemplo, puedes combinar los métodos startAt() y endAt() para limitar los resultados a un rango de valores específico.

Limita la cantidad de resultados

Puedes usar los métodos limitToFirst() y limitToLast() a fin de establecer una cantidad máxima de elementos secundarios que se sincronicen en un evento determinado. Por ejemplo, si usas limitToFirst() para establecer un límite de 100, inicialmente solo recibes hasta 100 eventos child_added. Si hay menos de 100 elementos almacenados en tu base de datos de Firebase, se activa un evento child_added por cada elemento.

A medida que los elementos cambian, recibes eventos child_added por los elementos que ingresan la búsqueda y eventos child_removed por los elementos que queden fuera para que la cantidad total permanezca en 100.

El siguiente ejemplo demuestra cómo una app de blog define una búsqueda para recuperar una lista de las 100 publicaciones más recientes de todos los usuarios:

Web

import { getDatabase, ref, query, limitToLast } from "firebase/database";

const db = getDatabase();
const recentPostsRef = query(ref(db, 'posts'), limitToLast(100));

Web

var recentPostsRef = firebase.database().ref('posts').limitToLast(100);

En este ejemplo, solo se define una búsqueda. Para sincronizar los datos realmente, se le debe adjuntar un objeto de escucha.

Filtra por clave o valor

Puedes usar startAt(), startAfter(), endAt(), endBefore() y equalTo() a fin de elegir puntos de inicio, finalización y equivalencia arbitrarios para las búsquedas. Esto puede ser útil para paginar datos o encontrar elementos con campos secundarios que tengan un valor específico.

Cómo se ordenan los datos de las consultas

En esta sección, se explica cómo se ordenan los datos en cada uno de los métodos de ordenamiento de la clase Query.

orderByChild

Cuando usas orderByChild(), los datos que contienen la clave secundaria especificada se ordenan de la siguiente manera:

  1. Los elementos secundarios cuyas claves secundarias especificadas posean el valor null irán en primer lugar.
  2. A continuación, aparecerán los elementos secundarios que tengan el valor false en la clave secundaria especificada. Si hay varios elementos secundarios con el valor false, se ordenan lexicográficamente por clave.
  3. A continuación, aparecerán los elementos secundarios que tengan el valor true en la clave secundaria especificada. Si hay varios elementos secundarios con el valor true, se ordenan lexicográficamente por clave.
  4. Luego vienen los elementos secundarios con valor numérico, que se ordenan en sentido ascendente. Si varios elementos secundarios tienen el mismo valor numérico en el nodo secundario especificado, se ordenan según la clave.
  5. Las strings van después de los números y se ordenan de manera lexicográfica, en sentido ascendente. Si varios elementos secundarios tienen el mismo valor en el nodo secundario especificado, se ordenan de manera lexicográfica según la clave.
  6. Los objetos quedan en último lugar y se ordenan de manera lexicográfica según su clave, en orden ascendente.

orderByKey

Cuando ordenas los datos con orderByKey(), estos se muestran en orden ascendente, según la clave.

  1. Los elementos secundarios con una clave que puede analizarse como un número entero de 32 bits van primero, ordenados en sentido ascendente.
  2. Los elementos secundarios con un valor de string como clave van después y ordenados de manera lexicográfica, en sentido ascendente.

orderByValue

Cuando usas orderByValue(), los elementos secundarios se ordenan según el valor. Se utilizan los mismos criterios de orden que para orderByChild(), excepto que se usa el valor del nodo en lugar del valor de una clave secundaria especificada.

Desvincula objetos de escucha

Para quitar las devoluciones de llamada, llama al método off() en tu referencia de la base de datos de Firebase.

Para quitar un solo objeto de escucha, puedes pasarlo como parámetro a off(). Si llamas a off() en la ubicación que no tiene argumentos, se quitarán todos los objetos de escucha de esa ubicación.

Si llamas a off() en un objeto de escucha primario, no se quitan automáticamente los objetos de escucha registrados en sus nodos secundarios. Deberás llamar a off() también en todos los objetos de escucha secundarios para quitar la devolución de llamada.

Próximos pasos