Cómo recuperar datos con Firebase Realtime Database para C++

En este documento, se tratan los aspectos básicos de la recuperación de datos y de cómo ordenar y filtrar datos en Firebase.

Antes de comenzar

Asegúrate de que la app esté configurada y de que puedas acceder a la base de datos, como se indica en la guía Get Started.

Cómo recuperar datos

Para recuperar datos en Firebase, debes invocar GetValue() o adjuntar un ValueListener en una referencia de FirebaseDatabase. El agente de escucha se invoca una vez para el estado inicial de los datos y otra vez cada vez que cambien los datos.

Obtén una DatabaseReference

Para escribir en la base de datos, necesitas una instancia de DatabaseReference:

    // Get the root reference location of the database.
    firebase::database::DatabaseReference dbref = database->GetReference();

Lee los datos una sola vez

Puedes usar el método GetValue() para leer una vez una instantánea estática del contenido de una ruta. El resultado de la tarea contendrá una instantánea con todos los datos de esa ubicación, incluidos los de nivel secundario. Si no hay datos, la instantánea tiene el valor null.

  firebase::Future&ltfirebase::database::DataSnapshot&gt result =
    dbRef.GetReference("Leaders").GetValue();

En este momento, la solicitud ya se hizo, pero tenemos que esperar a que se complete la interfaz Future antes de leer el valor. Dado que los juegos tienden a ejecutarse en bucle y usan menos devoluciones de llamadas que otras aplicaciones, lo normal es hacer un sondeo para determinar si se completó la operación.

  // In the game loop that polls for the result...

  if (result.status() != firebase::kFutureStatusPending) {
    if (result.status() != firebase::kFutureStatusComplete) {
      LogMessage("ERROR: GetValue() returned an invalid result.");
      // Handle the error...
    } else if (result.error() != firebase::database::kErrorNone) {
      LogMessage("ERROR: GetValue() returned error %d: %s", result.error(),
                 result.error_message());
      // Handle the error...
    } else {
      firebase::database::DataSnapshot snapshot = result.result();
      // Do something with the snapshot...
    }
  }

En este ejemplo, vemos una técnica básica de verificación de errores. Consulta la referencia firebase::Future para obtener más información sobre la verificación de errores y las maneras de determinar cuando el resultado está listo.

Detecta eventos

Puedes agregar agentes de escucha para suscribirte a los cambios en los datos:

Clase básica ValueListener

Devolución de llamada Uso común
OnValueChanged Lee y detecta cambios en todo el contenido de una ruta.

Clase básica OnChildListener

OnChildAdded Recupera listas de elementos o detecta elementos agregados a una lista. Se sugiere su uso con OnChildChanged y OnChildRemoved para supervisar los cambios en las listas.
OnChildChanged Detecta cambios en los elementos de una lista. Úsalo con OnChildAdded y OnChildRemoved para supervisar los cambios en las listas.
OnChildRemoved Detecta cuándo se quitan elementos de una lista. Úsalo con OnChildAdded y OnChildChanged para supervisar los cambios en las listas.
OnChildMoved Detecta cambios en el orden de los elementos de una lista ordenada. Las devoluciones de llamadas OnChildMoved siempre siguen a las devoluciones de llamadas OnChildChanged debido a que se modifica el orden de los elementos (en función del método de ordenamiento actual).

Clase ValueListener

Puedes usar las devoluciones de llamadas OnValueChanged para suscribirte a los cambios en el contenido de una ruta específica. Esta devolución de llamada se inicia cuando se adjunta el agente de escucha y nuevamente cada vez que cambian los datos (incluidos los de segundo nivel). La devolución de llamada recibe una instantánea que contiene todos los datos de dicha ubicación, incluidos los datos de nivel secundario. Si no hay datos, la instantánea tiene el valor null.

El siguiente ejemplo demuestra un juego que recupera los puntajes de una tabla de clasificación en la base de datos:

  class LeadersValueListener : public firebase::database::ValueListener {
   public:
    void OnValueChanged(
        const firebase::database::DataSnapshot& snapshot) override {
      // Do something with the data in snapshot...
    }
    void OnCancelled(const firebase::database::Error& error_code,
                     const char* error_message) override {
      LogMessage("ERROR: LeadersValueListener canceled: %d: %s", error_code,
                 error_message);
    }
  };

  // Elsewhere in the code...

  LeadersValueListener* listener = new LeadersValueListener();
  firebase::Future&ltfirebase::database::DataSnapshot&gt result =
    dbRef.GetReference("Leaders").AddValueListener(listener);

El resultado Future&ltDataSnaphot&gt contiene los datos de la ubicación específica en el momento del evento. Si llamas a value() sobre una instantánea, se muestra una Variant que representa los datos.

En este ejemplo, el método OnCancelled también se anula para ver si la lectura se cancela. Por ejemplo, una lectura puede cancelarse si el cliente no tiene permiso para leer datos de una ubicación en la base de datos de Firebase. El database::Error indicará por qué se produjo el error.

Clase ChildListener

Los eventos de nivel secundario se activan en respuesta a operaciones específicas que afectan a un elemento de nivel secundario de un nodo durante una operación, como cuando se agrega un nuevo elemento secundario mediante el método PushChild() o cuando se lo actualiza con el método UpdateChildren(). 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, un juego podría usar estos métodos en combinación para supervisar la actividad en los comentarios de una sesión del juego, como se muestra a continuación:

  class SessionCommentsChildListener : public firebase::database::ChildListener {
   public:
    void OnChildAdded(const firebase::database::DataSnapshot& snapshot,
                      const char* previous_sibling) override {
      // Do something with the data in snapshot ...
    }
    void OnChildChanged(const firebase::database::DataSnapshot& snapshot,
                        const char* previous_sibling) override {
      // Do something with the data in snapshot ...
    }
    void OnChildRemoved(
        const firebase::database::DataSnapshot& snapshot) override {
      // Do something with the data in snapshot ...
    }
    void OnChildMoved(const firebase::database::DataSnapshot& snapshot,
                      const char* previous_sibling) override {
      // Do something with the data in snapshot ...
    }
    void OnCancelled(const firebase::database::Error& error_code,
                     const char* error_message) override {
      LogMessage("ERROR: SessionCommentsChildListener canceled: %d: %s",
                 error_code, error_message);
    }
  };

  // elsewhere ....

  SessionCommentsChildListener* listener = new SessionCommentsChildListener();
  firebase::Future&ltfirebase::database::DataSnapshot&gt result =
    dbRef.GetReference("GameSessionComments").AddChildListener(listener);

La devolución de llamada OnChildAdded se usa normalmente para recuperar una lista de elementos en una base de datos de Firebase. La devolución de llamada OnChildAdded se invoca una vez por cada elemento secundario existente y otra vez cuando se agrega un nuevo elemento secundario a la ruta especificada. El agente de escucha recibe una instantánea que contiene los datos del nuevo elemento secundario.

La devolución de llamada OnChildChanged se invoca cada vez que se modifica un nodo secundario. Esto incluye cualquier modificación en descendientes del nodo secundario. Por lo general, se usa en combinación con OnChildAdded y OnChildRemoved en respuesta a cambios en una lista de elementos. La instantánea que se pasa al agente de escucha contiene los datos actualizados del elemento secundario.

La devolución de llamada OnChildRemoved se activa cuando se quita un elemento secundario inmediato. Por lo general, se usa en combinación con las devoluciones de llamadas OnChildAdded y OnChildChanged. La instantánea que se pasa a la devolución de llamada contiene los datos del elemento secundario que se quitó.

La devolución de llamada OnChildMoved se activa siempre que se genera una llamada OnChildChanged debido a una actualización que hace que se cambie el orden de ese elemento secundario. Se usa con datos ordenados mediante OrderByChild o OrderByValue.

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 organizado a 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.
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 invocas un método de ordenamiento varias veces en la misma consulta, se genera un error.

El siguiente ejemplo demuestra cómo podrías suscribirte a una tabla de clasificación de puntajes ordenada por puntaje.

  firebase::database::Query query =
    dbRef.GetReference("Leaders").OrderByChild("score");

  // To get the resulting DataSnapshot either use query.GetValue() and poll the
  // future, or use query.AddValueListener() and register to handle the
  // OnValueChanged callback.

Esto define una firebase::Query que, cuando se combina con un ValueListener, sincroniza el cliente con la tabla de clasificación en la base de datos, ordenada según la puntuación de cada entrada. Para obtener más información sobre cómo estructurar tus datos en forma eficiente, consulta Estructura tu base de datos.

La llamada al método OrderByChild() especifica la clave secundaria según la cual se deben ordenar los resultados. En este caso, los resultados se ordenan según el valor del valor "score" en cada elemento secundario. 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() Define la cantidad máxima de elementos que pueden mostrarse desde el final de la lista de resultados ordenada.
StartAt() Muestra elementos con un valor igual o superior a la clave o el valor que se especifica según el método de ordenamiento seleccionado.
EndAt() Muestra elementos con un valor inferior o igual a la clave o el valor que se especifica 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 y rango pueden combinarse. Por ejemplo, puedes combinar los métodos StartAt() y EndAt() para limitar los resultados a un rango de valores específico.

Incluso cuando hay una sola coincidencia para la consulta, la instantánea es una lista, aunque contenga un solo elemento.

Limita el número de resultados

Puedes usar los métodos LimitToFirst() y LimitToLast() para configurar una cantidad máxima de elementos secundarios que se deben sincronizar para una devolución de llamada específica. Por ejemplo, si usas LimitToFirst() para establecer un límite de 100, inicialmente solo recibes 100 devoluciones de llamada de tipo OnChildAdded. Si hay menos de 100 elementos almacenados en la base de datos de Firebase, se activa una devolución de llamada OnChildAdded por cada elemento.

A medida que los elementos cambien, recibirás devoluciones de llamadas de tipo OnChildAdded por los elementos que ingresen en la consulta y devoluciones de llamadas de tipo OnChildRemoved por los elementos que queden fuera para que el número total continúe siendo 100.

Por ejemplo, el siguiente fragmento de código muestra el primer puntaje de la tabla de clasificación:

  firebase::database::Query query =
    dbRef.GetReference("Leaders").OrderByChild("score").LimitToLast(1);

  // To get the resulting DataSnapshot either use query.GetValue() and poll the
  // future, or use query.AddValueListener() and register to handle the
  // OnValueChanged callback.

Filtra por clave o valor

Puedes usar StartAt(), EndAt() y EqualTo() para seleccionar puntos arbitrarios de inicio, fin y equivalencia para las consultas. Esto puede ser útil para paginar datos o para encontrar elementos con elementos 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 ordenarán 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 de manera lexicográfica según la 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 por clave, en orden ascendente.

OrderByKey

Cuando ordenas los datos con OrderByKey(), los datos se presentan en orden ascendente, según la clave.

  1. Los campos secundarios con una clave que puede analizarse como un elemento entero de 32 bits van primero, ordenados en sentido ascendente.
  2. Los campos secundarios con un valor de string como clave van posteriormente y ordenados de manera lexicográfica, en sentido ascendente.

OrderByValue

Cuando usas OrderByValue(), los elementos secundarios se ordenan según el valor. Los criterios de ordenamiento son los mismos que en OrderByChild(), pero se usa el valor del nodo en lugar del valor de una clave secundaria especificada.

Próximos pasos

Enviar comentarios sobre...

Si necesitas ayuda, visita nuestra página de asistencia.