Guardar datos

Antes de que empieces

Antes de poder utilizar Realtime Database , debe:

  • Registre su proyecto de Unity y configúrelo para usar Firebase.

    • Si tu proyecto de Unity ya usa Firebase, entonces ya está registrado y configurado para Firebase.

    • Si no tiene un proyecto de Unity, puede descargar una aplicación de muestra .

  • Agregue el SDK de Firebase Unity (específicamente, FirebaseDatabase.unitypackage ) a su proyecto de Unity.

Tenga en cuenta que agregar Firebase a su proyecto de Unity implica tareas tanto en Firebase console como en su proyecto de Unity abierto (por ejemplo, descarga archivos de configuración de Firebase desde la consola y luego los mueve a su proyecto de Unity).

Guardar datos

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

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

Obtener una referencia de base de datos

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

using Firebase;
using Firebase.Database;

public class MyScript: MonoBehaviour {
  void Start() {
    // Get the root reference location of the database.
    DatabaseReference reference = FirebaseDatabase.DefaultInstance.RootReference;
  }
}

Escribir, actualizar o eliminar datos en una referencia

Operaciones básicas de escritura

Para operaciones de escritura básicas, puede usar SetValueAsync() para guardar datos en una referencia específica, reemplazando cualquier dato existente en esa ruta. Puede utilizar este método para pasar tipos que correspondan a los tipos JSON disponibles de la siguiente manera:

  • string
  • long
  • double
  • bool
  • Dictionary<string, Object>
  • List<Object>

Si usa un objeto C# escrito, puede usar el JsonUtility.ToJson() integrado para convertir el objeto a Json sin formato y llamar a SetRawJsonValueAsync() . Por ejemplo, es posible que tenga una clase de Usuario con el siguiente aspecto:

public class User {
    public string username;
    public string email;

    public User() {
    }

    public User(string username, string email) {
        this.username = username;
        this.email = email;
    }
}

Puede agregar un usuario con SetRawJsonValueAsync() de la siguiente manera:

private void writeNewUser(string userId, string name, string email) {
    User user = new User(name, email);
    string json = JsonUtility.ToJson(user);

    mDatabaseRef.Child("users").Child(userId).SetRawJsonValueAsync(json);
}

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

mDatabaseRef.Child("users").Child(userId).Child("username").SetValueAsync(name);

Agregar a una lista de datos

Utilice el método Push() para agregar datos a una lista en aplicaciones multiusuario. El método Push() genera una clave única cada vez que se agrega un nuevo elemento secundario a la referencia de Firebase especificada. Al utilizar 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 generada por Push() se basa en una marca de tiempo, por lo que los elementos de la lista se ordenan automáticamente cronológicamente.

Puede utilizar la referencia a los nuevos datos devueltos por el método Push() para obtener el valor de la clave generada automáticamente por el niño o establecer datos para el niño. Llamar a Key en una referencia Push() 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 UpdateChildrenAsync() .

Al llamar UpdateChildrenAsync() , 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 la distribución en abanico de datos . Por ejemplo, un juego podría tener una clase LeaderboardEntry como esta:

public class LeaderboardEntry {
    public string uid;
    public int score = 0;

    public LeaderboardEntry() {
    }

    public LeaderboardEntry(string uid, int score) {
        this.uid = uid;
        this.score = score;
    }

    public Dictionary<string, Object> ToDictionary() {
        Dictionary<string, Object> result = new Dictionary<string, Object>();
        result["uid"] = uid;
        result["score"] = score;

        return result;
    }
}

Para crear un LeaderboardEntry y actualizarlo simultáneamente con la fuente de puntajes recientes y la lista de puntajes del usuario, el juego usa un código como este:

private void WriteNewScore(string userId, int score) {
    // Create new entry at /user-scores/$userid/$scoreid and at
    // /leaderboard/$scoreid simultaneously
    string key = mDatabase.Child("scores").Push().Key;
    LeaderBoardEntry entry = new LeaderBoardEntry(userId, score);
    Dictionary<string, Object> entryValues = entry.ToDictionary();

    Dictionary<string, Object> childUpdates = new Dictionary<string, Object>();
    childUpdates["/scores/" + key] = entryValues;
    childUpdates["/user-scores/" + userId + "/" + key] = entryValues;

    mDatabase.UpdateChildrenAsync(childUpdates);
}

Este ejemplo utiliza Push() 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 UpdateChildrenAsync() , como en este ejemplo se crea la nueva entrada en ambas ubicaciones. Las actualizaciones simultáneas realizadas de esta manera son atómicas: o todas las actualizaciones tienen éxito o todas fallan.

Borrar datos

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

También puede eliminar especificando null como valor para otra operación de escritura como SetValueAsync() o UpdateChildrenAsync() . Puede utilizar esta técnica con UpdateChildrenAsync() para eliminar varios elementos secundarios en una única llamada API.

Sepa cuándo se confirman sus datos.

Para saber cuándo sus datos se envían al servidor de Firebase Realtime Database, puede agregar una continuación. Tanto SetValueAsync() como UpdateChildrenAsync() devuelven una Task que le permite saber cuándo se completa la operación. Si la llamada no tiene éxito por algún motivo, Tasks IsFaulted será verdadera y la propiedad Exception indicará por qué ocurrió la falla.

Guardar datos como transacciones

Cuando trabaje con datos que podrían dañarse debido a modificaciones simultáneas, como contadores incrementales, puede utilizar una operación de transacción . Le asignas a esta operación un Func . Esta Func 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, se llama nuevamente a su función de actualización con el nuevo valor actual y se vuelve a intentar la escritura.

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

private void AddScoreToLeaders(string email, 
                               long score,
                               DatabaseReference leaderBoardRef) {

    leaderBoardRef.RunTransaction(mutableData => {
      List<object> leaders = mutableData.Value as List<object>

      if (leaders == null) {
        leaders = new List<object>();
      } else if (mutableData.ChildrenCount >= MaxScores) {
        long minScore = long.MaxValue;
        object minVal = null;
        foreach (var child in leaders) {
          if (!(child is Dictionary<string, object>)) continue;
          long childScore = (long)
                      ((Dictionary<string, object>)child)["score"];
          if (childScore < minScore) {
            minScore = childScore;
            minVal = child;
          }
        }
        if (minScore > score) {
          // The new score is lower than the existing 5 scores, abort.
          return TransactionResult.Abort();
        }

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

      // Add the new high score.
      Dictionary<string, object> newScoreMap =
                       new Dictionary<string, object>();
      newScoreMap["score"] = score;
      newScoreMap["email"] = email;
      leaders.Add(newScoreMap);
      mutableData.Value = leaders;
      return TransactionResult.Success(mutableData);
    });
}

El uso de una transacción evita que la tabla de clasificación sea incorrecta si varios usuarios registran puntuaciones al mismo tiempo o si el cliente tenía datos obsoletos. Si la transacción es rechazada, el servidor devuelve el valor actual al cliente, que ejecuta la transacción nuevamente 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 cualquier dato activo. Cuando se escriben datos, primero se escriben en esta versión local. Luego, el cliente de Firebase sincroniza esos datos con los servidores de bases de datos remotos y con otros clientes al "mejor esfuerzo".

Como resultado, todas las escrituras en la base de datos desencadenan eventos locales inmediatamente, antes de que se escriba cualquier 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 apropiado de eventos para que el cliente se sincronice con el estado actual del servidor, sin tener que escribir ningún código personalizado.

Próximos pasos