Catch up on everything announced at Firebase Summit, and learn how Firebase can help you accelerate app development and run your app with confidence. Learn More

Guardar datos con Firebase Realtime Database para C++

Organiza tus páginas con colecciones Guarda y categoriza el contenido según tus preferencias.

Empezar

Consulte primero la guía de Get Started si aún no ha configurado su aplicación y no ha accedido a la base de datos.

Obtener una referencia de base de datos

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

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

Guardar datos

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

Método Usos comunes
SetValue() Escriba o reemplace datos en una ruta definida, como users/<user-id>/<username> .
PushChild() Añadir a una lista de datos. Cada vez que llama a Push() , Firebase genera una clave única que también se puede usar como un identificador único, como user-scores/<user-id>/<unique-score-id> .
UpdateChildren() Actualice algunas de las claves para una ruta definida sin reemplazar todos los datos.
RunTransaction() Actualice datos complejos que podrían corromperse con actualizaciones simultáneas.

Escribir, actualizar o eliminar datos en una referencia

Operaciones básicas de escritura

Para operaciones básicas de escritura, puede usar SetValue() para guardar datos en una referencia específica, reemplazando cualquier dato existente en esa ruta. Puede usar este método para pasar tipos aceptados por JSON a través de un tipo Variant que admita:

  • Nulo (esto elimina los datos)
  • Enteros (64 bits)
  • Números de punto flotante de precisión doble
  • Booleanos
  • Instrumentos de cuerda
  • Vectores de variantes
  • Mapas de cadenas a variantes

El uso SetValue() de esta manera sobrescribe los datos en la ubicación especificada, incluidos los nodos secundarios. Sin embargo, aún puede actualizar un elemento secundario sin volver a escribir todo el objeto. Si desea permitir que los usuarios actualicen sus perfiles, puede actualizar el nombre de usuario de la siguiente manera:

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

Agregar a una lista de datos

Utilice 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 nuevo elemento secundario a la referencia de Firebase especificada. Mediante el uso de estas claves generadas automáticamente para cada nuevo elemento de la lista, varios clientes pueden agregar niños a la misma ubicación al mismo tiempo sin conflictos de escritura. La clave única generada por PushChild() se basa en una marca de tiempo, por lo que los elementos de la lista se ordenan cronológicamente automáticamente.

Puede usar la referencia a los nuevos datos devueltos por el método PushChild() para obtener el valor de la clave generada automáticamente del niño o establecer datos para el niño. Llamar GetKey() en una referencia PushChild() devuelve el valor de la clave generada automáticamente.

Actualizar campos específicos

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

Al llamar a UpdateChildren() , puede actualizar los valores secundarios de nivel inferior especificando una ruta para la clave. Si los datos se almacenan en varias ubicaciones para escalar mejor, puede actualizar todas las instancias de esos datos mediante distribución de datos . Por ejemplo, un juego podría tener una clase LeaderboardEntry como esta:

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

 public:
  LeaderboardEntry() {
  }

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

  std::map<std::string, Object> ToMap() {
    std::map<string, Variant> result = new std::map<string, Variant>();
    result["uid"] = Variant(uid);
    result["score"] = Variant(score);

    return result;
  }
}

Para crear un LeaderboardEntry y actualizarlo simultáneamente con la fuente de puntuación reciente y la propia lista de puntuación del usuario, el juego utiliza 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<std::string, Variant> entryValues = entry.ToMap();

  std::map<string, Variant> childUpdates = new std::map<string, Variant>();
  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 recuperar simultáneamente la clave 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, puede realizar actualizaciones simultáneas en varias ubicaciones en el árbol JSON con una sola llamada a UpdateChildren() , como en este ejemplo, se crea la nueva entrada en ambas ubicaciones. Las actualizaciones simultáneas realizadas de esta manera son atómicas: todas las actualizaciones se realizan correctamente o todas fallan.

Borrar datos

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

También puede eliminar especificando una Variant null como valor para otra operación de escritura, como SetValue() o UpdateChildren() . Puede usar esta técnica con UpdateChildren() para eliminar varios elementos secundarios en una sola llamada a la API.

Sepa cuándo se comprometen sus datos.

Para saber cuándo se confirman sus datos en el servidor de base de datos en tiempo real de Firebase, consulte el resultado Futuro para ver si es correcto.

Guardar datos como transacciones

Cuando trabaje con datos que podrían corromperse por modificaciones simultáneas, como contadores incrementales, puede usar una operación de transacción . Le da a esta operación una función DoTransaction . Esta función de actualización toma el estado actual de los datos como argumento y devuelve el nuevo estado deseado que le gustaría escribir. Si otro cliente escribe en la ubicación antes de que su nuevo valor se escriba correctamente, su función de actualización se vuelve a llamar con el nuevo valor actual y se vuelve a intentar la escritura.

Por ejemplo, en un juego podría 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() >= MaxScores) {
      long minScore = LONG_MAX;
      MutableData *minVal = null;
      std::vector<MutableData> children = mutableData.children();
      std::vector<MutableData>::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 < minScore) {
          minScore = childScore;
          minVal = &*it;
        }
      }
      if (minScore > 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<std::string, Variant> newScoreMap =
      new std::map<std::string, Variant>();
    newScoreMap["score"] = score;
    newScoreMap["email"] = email;
    children.Add(newScoreMap);
    mutableData->set_value(children);
    return kTransactionResultSuccess;
  });
}

El uso de una transacción evita que la tabla de clasificación sea incorrecta si varios usuarios registran puntajes al mismo tiempo o si el cliente tiene datos obsoletos. Si se rechaza la transacción, el servidor devuelve el valor actual al cliente, que vuelve a ejecutar la transacción con el valor actualizado. Esto se repite hasta que se acepta la transacción o se han realizado demasiados intentos.

Escribir datos sin conexión

Si un cliente pierde su conexión de red, su aplicación seguirá funcionando correctamente.

Cada cliente conectado a una base de datos de Firebase mantiene su propia versión interna de los datos activos. Cuando se escriben datos, primero se escriben en esta versión local. Luego, el cliente de Firebase sincroniza esos datos con los servidores de base de datos remotos y con otros clientes en base al "mejor esfuerzo".

Como resultado, todas las escrituras en la base de datos desencadenan eventos locales inmediatamente, antes de que se escriba ningún dato en el servidor. Esto significa que su aplicación sigue respondiendo independientemente de la latencia o la conectividad de la red.

Una vez que se restablece la conectividad, su aplicación recibe el conjunto de eventos adecuado para que el cliente se sincronice con el estado actual del servidor, sin tener que escribir ningún código personalizado.

Próximos pasos