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

Cómo comenzar

Si aún no configuraste la app ni el acceso a la base de datos, primero consulta la guía Get Started.

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();

Cómo guardar datos

Existen cuatro métodos para escribir datos en Firebase Realtime Database:

Método Usos comunes
SetValue() Escribir o reemplazar datos en una ruta de acceso definida, como users/<user-id>/<username>.
PushChild() Agregar a una lista de datos. Cada vez que llamas a Push(), Firebase genera una clave única que también se puede usar como identificador único, como user-scores/<user-id>/<unique-score-id>.
UpdateChildren() Actualizar algunas de las claves de una ruta de acceso definida sin reemplazar todos los datos.
RunTransaction() Actualizar datos complejos que pueden dañarse con actualizaciones simultáneas.

Escribe, actualiza o borra datos de una referencia

Operaciones básicas de escritura

Si quieres ejecutar operaciones básicas de escritura, puedes usar SetValue() para guardar datos en una referencia específica y reemplazar todos los datos en esa ruta. Puedes usar este método para pasar tipos aceptados por JSON a través de un tipo de variante compatible con lo siguiente:

  • Null (esto borra los datos)
  • Enteros (64 bits)
  • Números de coma flotante con precisión doble
  • Booleanos
  • Strings
  • Vectores de variantes
  • Mapas de strings a variantes

El uso de SetValue() de esta forma sobrescribe datos en la ubicación especificada, incluidos todos los nodos secundarios. Sin embargo, es posible actualizar un elemento secundario sin volver a escribir el objeto entero. Si deseas permitir que los usuarios actualicen sus perfiles, podrías actualizar el nombre de usuario de la siguiente forma:

dbref.Child("users").Child(userId).Child("username").SetValue(name);

Agrega datos a una lista de datos

Usa el método PushChild() para agregar datos a una lista en aplicaciones multiusuario. El método PushChild() genera una clave única cada vez que se agrega un elemento secundario nuevo a la referencia de Firebase especificada. Cuando se usan estas claves generadas de forma automática para cada elemento nuevo de la lista, varios clientes pueden agregar elementos secundarios a la misma ubicación, al mismo tiempo y sin conflictos de escritura. PushChild() genera la clave única a partir de una marca de tiempo, por lo que sus elementos se ordenan de forma automática y cronológica.

Puedes usar la referencia a los datos nuevos que dio como resultado el método PushChild() para obtener el valor de la clave del elemento secundario generada de forma automática o para configurar datos para el elemento secundario. Llamar a GetKey() en una referencia de PushChild() da como resultado el valor de la clave generada de forma automática.

Actualiza campos específicos

Para escribir de forma simultánea en elementos secundarios específicos de un nodo sin sobrescribir otros nodos secundarios, usa el método UpdateChildren().

Cuando llamas a UpdateChildren(), puedes especificar una ruta de acceso de la clave para actualizar valores secundarios de nivel inferior. Si se almacenan datos en varias ubicaciones para obtener un escalamiento mejor, puedes actualizar todas las instancias de esos datos mediante la distribución de datos. Por ejemplo, un juego puede tener una clase LeaderboardEntry como la siguiente:

class LeaderboardEntry {
  std::string uid;
  int score = 0;

 public:
  LeaderboardEntry() {
  }

  LeaderboardEntry(std::string uid, int score) {
    this->uid = uid;
    this->score = score;
  }

  std::map&ltstd::string, Object&gt ToMap() {
    std::map&ltstring, Variant&gt result = new std::map&ltstring, Variant&gt();
    result["uid"] = Variant(uid);
    result["score"] = Variant(score);

    return result;
  }
}

Para crear una LeaderboardEntry y actualizarla de forma simultánea con el feed de puntuación reciente y la lista de puntuaciones propia del usuario, el juego usa el siguiente código:

void WriteNewScore(std::string userId, int score) {
  // Create new entry at /user-scores/$userid/$scoreid and at
  // /leaderboard/$scoreid simultaneously
  std::string key = dbref.Child("scores").PushChild().GetKey();
  LeaderBoardEntry entry = new LeaderBoardEntry(userId, score);
  std::map&ltstd::string, Variant&gt entryValues = entry.ToMap();

  std::map&ltstring, Variant&gt childUpdates = new std::map&ltstring, Variant&gt();
  childUpdates["/scores/" + key] = entryValues;
  childUpdates["/user-scores/" + userId + "/" + key] = entryValues;

  dbref.UpdateChildren(childUpdates);
}

Este ejemplo usa PushChild() para crear una entrada en el nodo que contiene entradas para todos los usuarios en /scores/$key y recupera la clave de forma simultánea con key(). Luego, la clave se puede usar para crear una segunda entrada en las puntuaciones del usuario en /user-scores/$userid/$key.

Con estas rutas de acceso, puedes ejecutar actualizaciones simultáneas en varias ubicaciones del árbol JSON con una única llamada a UpdateChildren(), tal como este ejemplo crea la entrada nueva en ambas ubicaciones. Las actualizaciones simultáneas que se ejecutan de esta forma son atómicas: todas las actualizaciones se aplican correctamente o todas fallan.

Borra datos

La forma más sencilla de borrar datos es llamar a RemoveValue() en una referencia a la ubicación de los datos.

Para borrar, también puedes especificar una null Variant como valor de otra operación de escritura, como SetValue() o UpdateChildren(). Puedes usar esta técnica con UpdateChildren() para borrar varios elementos secundarios con una única llamada de la API.

Conoce cuándo se envían los datos

Para saber cuándo se envían los datos al servidor de Firebase Realtime Database, verifica que el resultado de Future sea correcto.

Guarda datos como transacciones

Cuando trabajas con datos que se podrían dañar si se hacen cambios simultáneos (por ejemplo, contadores incrementales) puedes usar una operación de transacción. A esta operación debes asignarle una función DoTransaction. La función de actualización toma el estado actual de los datos como argumento y da como resultado el nuevo estado que deseas escribir. Si otro cliente escribe en la ubicación antes de que tu valor nuevo se escriba correctamente, se hace un nuevo llamado a la función de actualización con el nuevo valor actual y se vuelve a intentar la operación de escritura.

Por ejemplo, en un juego, podrías permitir que los usuarios actualicen una tabla de clasificación con las cinco puntuaciones más altas:

void AddScoreToLeaders(std::string email,
                       long score,
                       DatabaseReference leaderBoardRef) {
  leaderBoardRef.RunTransaction([](firebase::database::MutableData* mutableData) {
    if (mutableData.children_count() &gt= MaxScores) {
      long minScore = LONG_MAX;
      MutableData *minVal = null;
      std::vector&ltMutableData&gt children = mutableData.children();
      std::vector&ltMutableData&gt::iterator it;
      for (it = children.begin(); it != children.end(); ++it) {
        if (!it->value().is_map())
          continue;
        long childScore = (long)it->Child("score").value().int64_value();
        if (childScore &lt minScore) {
          minScore = childScore;
          minVal = &amp*it;
        }
      }
      if (minScore &gt score) {
        // The new score is lower than the existing 5 scores, abort.
        return kTransactionResultAbort;
      }

      // Remove the lowest score.
      children.Remove(minVal);
    }

    // Add the new high score.
    std::map&ltstd::string, Variant&gt newScoreMap =
      new std::map&ltstd::string, Variant&gt();
    newScoreMap["score"] = score;
    newScoreMap["email"] = email;
    children.Add(newScoreMap);
    mutableData->set_value(children);
    return kTransactionResultSuccess;
  });
}

Si usas una transacción, impides que la tabla de clasificación sea incorrecta en caso de que varios usuarios registren puntuaciones al mismo tiempo o el cliente tenga datos inactivos. Si se rechaza la transacción, el servidor le muestra el valor actual al cliente, que vuelve a ejecutar la transacción con el valor actualizado. Esto se repite hasta que se acepte la transacción o hasta que se registren demasiados intentos.

Escribe datos sin conexión

Si un cliente pierde la conexión de red, la app continuará funcionando de manera correcta.

Todos los clientes conectados a una base de datos de Firebase mantienen su propia versión interna de los datos activos. Cuando se escriben datos, se hace primero en esta versión local. Después, el cliente de Firebase sincroniza esos datos con los servidores de bases de datos remotas y con otros clientes según el “mejor esfuerzo”.

Como resultado, todas las operaciones de escritura en la base de datos activan eventos locales de inmediato, antes de que se escriban datos en el servidor. Esto significa que la app conserva su capacidad de respuesta, sin importar la latencia o el estado de conexión de la red.

Cuando se restablece la conexión, tu app recibe el conjunto de eventos adecuado, de manera que el cliente se sincroniza con el estado actual del servidor sin tener que escribir código personalizado.

Pasos siguientes

Enviar comentarios sobre…

¿Necesitas ayuda? Visita nuestra página de asistencia.