Join us at MongoDB.local London on 7 May to unlock new possibilities for your data. Use WEB50 to save 50%.
Register now >
Docs Menu
Docs Home
/ /
Sync Data

Manual Client Reset Data Recovery - React Native SDK

Esta página explica cómo recuperar manualmente datos de reino no sincronizados después de un reinicio de cliente usando el modo de reinicio de cliente Recuperación manual.

Manual recovery requires significant amounts of code, schema concessions, and custom conflict resolution logic. You should only perform a manual recovery of unsynced realm data if you cannot lose unsynced data and the other automatic client reset methods do not meet your use case.

Para obtener más información sobre otros modos de restablecimiento de cliente disponibles, consulte Restablecer un reino de cliente.

Los detalles de la recuperación manual dependen en gran medida de la aplicación y el esquema. Sin embargo, existen algunas técnicas que pueden ayudar con las recuperaciones manuales. La sección Seguimiento de cambios por estrategia de objeto demuestra un método para recuperar cambios no sincronizados durante un reinicio del cliente.

Advertencia

Avoid Making Breaking Schema Changes in Production

Do not expect to recover all unsynced data after a breaking schema change. The best way to preserve user data is to never make a breaking schema change at all.

Importante

Los cambios importantes en el esquema requieren una actualización del esquema de la aplicación

Después de un cambio de esquema importante:

  • All clients must perform a client reset.

  • Debe actualizar los modelos de cliente afectados por el cambio de esquema importante.

La estrategia de recuperación de datos de restablecimiento del cliente manual rastrear cambios por objeto permite recuperar datos ya escritos en el archivo Realm del cliente, pero que aún no han sido sincronizados con el backend.

En esta estrategia, agregas un "Última hora de actualización" a cada Modelo de objeto para rastrear cuándo fue la última vez que cambió cada objeto. Supervisaremos para determinar cuándo fue la última vez que el realm subió su estado al backend.

When backend invokes a client reset, find objects that were deleted, created, or updated since the last sync with the backend. Then copy that data from the backup realm to the new realm.

Los siguientes pasos demuestran cómo implementar el proceso a un alto nivel:

  1. Client reset error: Your application receives a client reset error code from the backend.

  2. Strategy implementation: The SDK calls your strategy implementation.

  3. Cerrar todas las instancias del dominio: Cierre todas las instancias abiertas del dominio que experimenta el reinicio del cliente. Si la arquitectura de su aplicación lo dificulta (por ejemplo, si utiliza varias instancias del dominio simultáneamente en escuchas de toda la aplicación), puede ser más sencillo reiniciar la aplicación. Puede hacerlo mediante programación o mediante una solicitud directa al usuario en un diálogo.

  4. Move the realm to a backup file: Llame a Realm.App.Sync.initiateClientReset() método estático. Este método mueve la copia actual del archivo Realm del cliente a un archivo de copia de seguridad.

  5. Open new instance of the realm: Open a new instance of the realm using your typical sync configuration. If your application uses multiple realms, you can identify the realm experiencing a client reset from the backup file name.

  6. Descargar todos los datos del realm desde el backend: Descarga el conjunto completo de datos del realm antes de continuar. Este es el comportamiento por defecto del objeto FlexibleSyncConfiguration.

  7. Abra la copia de seguridad del reino: utilice el error.config objeto pasado como argumento a la función de devolución de llamada SyncConfiguration.error.

  8. Migrar cambios no sincronizados: Consulta el realm de copia de seguridad para recuperar datos. Inserta, borra o actualiza datos en el nuevo realm según sea necesario.

Este ejemplo demuestra cómo implementar la estrategia de recuperación de datos de restablecimiento manual del cliente mediante seguimiento de cambios de objetos.

Nota

Limitations of This Example

  • Este ejemplo solo aplica a una aplicación con un único dominio que contiene un único tipo de objeto de dominio. Para cada tipo de objeto adicional, deberá agregar otro detector de sincronización, como se describe en la sección "Seguimiento de la sincronización en dominios separados".

  • This example keeps track of the last time each object was updated. As a result, the recovery operation overwrites the entire object in the new realm if any field was updated after the last successful sync of the backup realm. This could overwrite fields updated by other clients with old data from this client. If your realm objects contain multiple fields containing important data, consider keeping track of the last updated time of each field instead, and recovering each field individually.

Para obtener más información sobre otras formas de realizar un restablecimiento manual del cliente con recuperación de datos, consulte la sección Estrategias alternativas.

1

Agrega una nueva propiedad a tu esquema de objetos Realm para rastrear la última vez que se actualizó. Siempre que crees o actualices un objeto Realm con el esquema, incluye una marca de tiempo con la hora de la actualización.

Ordinarily, there is no way to detect when a Realm object was last modified. This makes it difficult to determine which changes were synced to the backend. By adding a timestamp lastUpdated to your Realm object models and updating that timestamp to the current time whenever a change occurs, you can keep track of when objects were changed.

const DogSchema = {
name: "Dog",
properties: {
name: "string",
age: "int?",
lastUpdated: "int",
},
};
2

En la FlexibleSyncConfiguration del realm, establezca el campo clientReset en modo manual e incluya una función de retorno error. Definirás la función de devolución de llamada de error en el Crear devolución de llamada para gestionar la sección de restablecimiento del cliente.

const config = {
schema: [DogSchema],
sync: {
user: app.currentUser,
partitionValue: "MyPartitionValue",
clientReset: {
mode: "manual",
},
error: handleSyncError, // callback function defined later
},
};
3

Just knowing when objects were changed isn't enough to recover data during a client reset. You also need to know when the realm last completed a sync successfully. This example implementation uses a singleton object in a separate realm called LastSynced paired with a change listener to record when a realm finishes syncing successfully.

Define your LastSynced Realm to track the latest time your realm synchronizes.

const LastSyncedSchema = {
name: "LastSynced",
properties: {
realmTracked: "string",
timestamp: "int?",
},
primaryKey: "realmTracked",
};
const lastSyncedConfig = { schema: [LastSyncedSchema] };
const lastSyncedRealm = await Realm.open(lastSyncedConfig);
lastSyncedRealm.write(() => {
lastSyncedRealm.create("LastSynced", {
realmTracked: "Dog",
});
});

Register a change listener to subscribe to changes to the Dog collection. Only update the LastSynced object if the sync session is connected and all local changes have been synced with the server.

// Listens for changes to the Dogs collection
realm.objects("Dog").addListener(async () => {
// only update LastSynced if sync session is connected
// and all local changes are synced
if (realm.syncSession.isConnected()) {
await realm.syncSession.uploadAllLocalChanges();
lastSyncedRealm.write(() => {
lastSyncedRealm.create("LastSynced", {
realmTracked: "Dog",
timestamp: Date.now(),
});
});
}
});
4

Ahora que ya has registrado los tiempos de actualización de todos los objetos de la aplicación, así como la última vez que la aplicación completó una sincronización, es hora de implementar el proceso de recuperación manual. Este ejemplo gestiona dos operaciones principales de recuperación:

  • Restore unsynced inserts and updates from the backup realm

  • Borra los objetos con el estado NUEVO REALM que antes se borraron del realm de copia de seguridad.

You can follow along with the implementation of these operations in the code samples below.

async function handleSyncError(_session, error) {
if (error.name === "ClientReset") {
const realmPath = realm.path; // realm.path will not be accessible after realm.close()
realm.close(); // you must close all realms before proceeding
// pass your realm app instance and realm path to initiateClientReset()
Realm.App.Sync.initiateClientReset(app, realmPath);
// Redownload the realm
realm = await Realm.open(config);
const oldRealm = await Realm.open(error.config);
const lastSyncedTime = lastSyncedRealm.objectForPrimaryKey(
"LastSynced",
"Dog"
).timestamp;
const unsyncedDogs = oldRealm
.objects("Dog")
.filtered(`lastUpdated > ${lastSyncedTime}`);
// add unsynced dogs to synced realm
realm.write(() => {
unsyncedDogs.forEach((dog) => {
realm.create("Dog", dog, "modified");
});
});
// delete dogs from synced realm that were deleted locally
const syncedDogs = realm
.objects("Dog")
.filtered(`lastUpdated <= ${lastSyncedTime}`);
realm.write(() => {
syncedDogs.forEach((dog) => {
if (!oldRealm.objectForPrimaryKey("Dog", dog._id)) {
realm.delete(dog);
}
});
});
// make sure everything syncs and close old realm
await realm.syncSession.uploadAllLocalChanges();
oldRealm.close();
} else {
console.log(`Received error ${error.message}`);
}
}

Possible alternate implementations include:

  • Overwrite the entire backend with the backup state: With no "last updated time" or "last synced time", upsert all objects from the backup realm into the new realm. There is no way to recovered unsynced deletions with this approach. This approach overwrites all data written to the backend by other clients since the last sync. Recommended for applications where only one user writes to each realm.

  • Rastrear cambios por campo: en lugar de rastrear la 'última vez de actualización' para cada objeto, rastrear la 'última vez de actualización' para cada campo. Actualizar los campos individualmente utilizando esta lógica para evitar sobrescribir los guardados de campos de otros clientes con datos antiguos. Recomendado para aplicaciones con muchos campos por objeto donde los conflictos deben resolverse a nivel de campo.

  • Track updates separately from objects: Instead of tracking a "last updated time" in the schema of each object, create another model in your schema called Updates. Every time any field in any object (besides Updates) updates, record the primary key, field, and time of the update. During a client reset, "re-write" all of the Update events that occurred after the "last synced time" using the latest value of that field in the backup realm. This approach should replicate all unsynced local changes in the new realm without overwriting any fields with stale data. However, storing the collection of updates could become expensive if your application writes frequently. Recommended for applications where adding "lastUpdated" fields to object models is undesirable.

Volver

Manejar errores de sincronización

En esta página