Habilita datos sin conexión

Firestore admite la persistencia de datos sin conexión. Esta función almacena en caché una copia de los datos de Firestore que la app usa de forma activa, por lo que puede acceder a los datos cuando el dispositivo está sin conexión. Puedes escribir, leer, escuchar y consultar los datos en caché. Cuando el dispositivo vuelve a estar en línea, Firestore sincroniza los cambios locales que la app realizó en el backend de Firestore.

A fin de usar la persistencia sin conexión, no es necesario realizar ningún cambio en el código para acceder a los datos de Firestore. Cuando está activada la persistencia de datos sin conexión, la biblioteca cliente de Firestore administra el acceso a los datos en línea y sin conexión de forma automática, y sincroniza los datos locales cuando vuelve a conectarse el dispositivo.

Configura la persistencia sin conexión

Cuando inicialices Firestore, podrás habilitar o inhabilitar la persistencia sin conexión:

  • En las plataformas de Android y Apple, la persistencia sin conexión está habilitada de forma predeterminada. Para inhabilitar la persistencia, configura la opción PersistenceEnabled en false.
  • En la Web, la persistencia sin conexión está inhabilitada de forma predeterminada. Para habilitar la persistencia, llama al método enablePersistence. La caché de Firestore no se borra de forma automática entre sesiones. Por lo tanto, si la aplicación web administra información sensible, asegúrate de preguntarle al usuario si se encuentra en un dispositivo de confianza antes de habilitar la persistencia.

Web versión 9

import { enableIndexedDbPersistence } from "firebase/firestore";

enableIndexedDbPersistence(db)
  .catch((err) => {
      if (err.code == 'failed-precondition') {
          // Multiple tabs open, persistence can only be enabled
          // in one tab at a a time.
          // ...
      } else if (err.code == 'unimplemented') {
          // The current browser does not support all of the
          // features required to enable persistence
          // ...
      }
  });
// Subsequent queries will use persistence, if it was enabled successfully

Web versión 8

firebase.firestore().enablePersistence()
  .catch((err) => {
      if (err.code == 'failed-precondition') {
          // Multiple tabs open, persistence can only be enabled
          // in one tab at a a time.
          // ...
      } else if (err.code == 'unimplemented') {
          // The current browser does not support all of the
          // features required to enable persistence
          // ...
      }
  });
// Subsequent queries will use persistence, if it was enabled successfully
Swift
Nota: Este producto no se encuentra disponible en los destinos de watchOS ni de App Clip.
let settings = FirestoreSettings()
settings.isPersistenceEnabled = true

// Any additional options
// ...

// Enable offline data persistence
let db = Firestore.firestore()
db.settings = settings
Objective‑C
Nota: Este producto no está disponible en los destinos de watchOS ni de App Clip.
FIRFirestoreSettings *settings = [[FIRFirestoreSettings alloc] init];
settings.persistenceEnabled = YES;

// Any additional options
// ...

// Enable offline data persistence
FIRFirestore *db = [FIRFirestore firestore];
db.settings = settings;
Java
Android
FirebaseFirestoreSettings settings = new FirebaseFirestoreSettings.Builder()
        .setPersistenceEnabled(true)
        .build();
db.setFirestoreSettings(settings);
Kotlin+KTX
Android
val settings = firestoreSettings {
    isPersistenceEnabled = true
}
db.firestoreSettings = settings

Configura el tamaño de la caché

Cuando la persistencia está habilitada, Firestore almacena en caché todos los documentos recibidos del backend para el acceso sin conexión. Firestore establece un límite predeterminado para el tamaño de la caché. Después de superarlo, Firestore intenta borrar de forma periódica los documentos antiguos que no se usan. Puedes configurar un umbral de tamaño distinto para la caché o inhabilitar completamente el proceso de limpieza:

Web versión 9

import { initializeFirestore, CACHE_SIZE_UNLIMITED } from "firebase/firestore";

const firestoreDb = initializeFirestore(app, {
  cacheSizeBytes: CACHE_SIZE_UNLIMITED
});

Web versión 8

firebase.firestore().settings({
    cacheSizeBytes: firebase.firestore.CACHE_SIZE_UNLIMITED
});
Swift
Nota: Este producto no se encuentra disponible en los destinos de watchOS ni de App Clip.
// The default cache size threshold is 100 MB. Configure "cacheSizeBytes"
// for a different threshold (minimum 1 MB) or set to "FirestoreCacheSizeUnlimited"
// to disable clean-up.
let settings = Firestore.firestore().settings
settings.cacheSizeBytes = FirestoreCacheSizeUnlimited
Firestore.firestore().settings = settings
Objective‑C
Nota: Este producto no está disponible en los destinos de watchOS ni de App Clip.
// The default cache size threshold is 100 MB. Configure "cacheSizeBytes"
// for a different threshold (minimum 1 MB) or set to "kFIRFirestoreCacheSizeUnlimited"
// to disable clean-up.
FIRFirestoreSettings *settings = [FIRFirestore firestore].settings;
settings.cacheSizeBytes = kFIRFirestoreCacheSizeUnlimited;
[FIRFirestore firestore].settings = settings;
  
Java
Android

// The default cache size threshold is 100 MB. Configure "setCacheSizeBytes"
// for a different threshold (minimum 1 MB) or set to "CACHE_SIZE_UNLIMITED"
// to disable clean-up.
FirebaseFirestoreSettings settings = new FirebaseFirestoreSettings.Builder()
        .setCacheSizeBytes(FirebaseFirestoreSettings.CACHE_SIZE_UNLIMITED)
        .build();
db.setFirestoreSettings(settings);
Kotlin+KTX
Android

// The default cache size threshold is 100 MB. Configure "setCacheSizeBytes"
// for a different threshold (minimum 1 MB) or set to "CACHE_SIZE_UNLIMITED"
// to disable clean-up.
val settings = FirebaseFirestoreSettings.Builder()
        .setCacheSizeBytes(FirebaseFirestoreSettings.CACHE_SIZE_UNLIMITED)
        .build()
db.firestoreSettings = settings

Supervisa datos sin conexión

Si no tienes conexión en el dispositivo pero está habilitada la persistencia sin conexión, los objetos de escucha recibirán eventos cuando cambien los datos almacenados en la caché local. Los eventos de escucha pueden relacionarse con documentos, colecciones y consultas.

Para comprobar si estás recibiendo datos del servidor o de la caché, usa la propiedad fromCache en los SnapshotMetadata del evento de instantánea. Si fromCache es true, los datos provienen de la caché y es posible que sean obsoletos o estén incompletos. Si fromCache es false, los datos están completos e incorporan las últimas actualizaciones del servidor.

Según la configuración predeterminada, no se genera ningún evento si solo cambian los SnapshotMetadata. Si utilizas los valores de fromCache, especifica la opción de escucha includeMetadataChanges cuando conectes el controlador de escucha.

Web versión 9

import { collection, onSnapshot, where, query } from "firebase/firestore";

const q = query(collection(db, "cities"), where("state", "==", "CA"));
onSnapshot(q, { includeMetadataChanges: true }, (snapshot) => {
    snapshot.docChanges().forEach((change) => {
        if (change.type === "added") {
            console.log("New city: ", change.doc.data());
        }

        const source = snapshot.metadata.fromCache ? "local cache" : "server";
        console.log("Data came from " + source);
    });
});

Web versión 8

db.collection("cities").where("state", "==", "CA")
  .onSnapshot({ includeMetadataChanges: true }, (snapshot) => {
      snapshot.docChanges().forEach((change) => {
          if (change.type === "added") {
              console.log("New city: ", change.doc.data());
          }

          var source = snapshot.metadata.fromCache ? "local cache" : "server";
          console.log("Data came from " + source);
      });
  });
Swift
Nota: Este producto no se encuentra disponible en los destinos de watchOS ni de App Clip.
// Listen to metadata updates to receive a server snapshot even if
// the data is the same as the cached data.
db.collection("cities").whereField("state", isEqualTo: "CA")
    .addSnapshotListener(includeMetadataChanges: true) { querySnapshot, error in
        guard let snapshot = querySnapshot else {
            print("Error retreiving snapshot: \(error!)")
            return
        }

        for diff in snapshot.documentChanges {
            if diff.type == .added {
                print("New city: \(diff.document.data())")
            }
        }

        let source = snapshot.metadata.isFromCache ? "local cache" : "server"
        print("Metadata: Data fetched from \(source)")
}
Objective‑C
Nota: Este producto no está disponible en los destinos de watchOS ni de App Clip.
// Listen to metadata updates to receive a server snapshot even if
// the data is the same as the cached data.
[[[db collectionWithPath:@"cities"] queryWhereField:@"state" isEqualTo:@"CA"]
    addSnapshotListenerWithIncludeMetadataChanges:YES
    listener:^(FIRQuerySnapshot *snapshot, NSError *error) {
      if (snapshot == nil) {
        NSLog(@"Error retreiving snapshot: %@", error);
        return;
      }
      for (FIRDocumentChange *diff in snapshot.documentChanges) {
        if (diff.type == FIRDocumentChangeTypeAdded) {
          NSLog(@"New city: %@", diff.document.data);
        }
      }

      NSString *source = snapshot.metadata.isFromCache ? @"local cache" : @"server";
      NSLog(@"Metadata: Data fetched from %@", source);
    }];
Java
Android
db.collection("cities").whereEqualTo("state", "CA")
        .addSnapshotListener(MetadataChanges.INCLUDE, new EventListener<QuerySnapshot>() {
            @Override
            public void onEvent(@Nullable QuerySnapshot querySnapshot,
                                @Nullable FirebaseFirestoreException e) {
                if (e != null) {
                    Log.w(TAG, "Listen error", e);
                    return;
                }

                for (DocumentChange change : querySnapshot.getDocumentChanges()) {
                    if (change.getType() == Type.ADDED) {
                        Log.d(TAG, "New city:" + change.getDocument().getData());
                    }

                    String source = querySnapshot.getMetadata().isFromCache() ?
                            "local cache" : "server";
                    Log.d(TAG, "Data fetched from " + source);
                }

            }
        });
Kotlin+KTX
Android
db.collection("cities").whereEqualTo("state", "CA")
        .addSnapshotListener(MetadataChanges.INCLUDE) { querySnapshot, e ->
            if (e != null) {
                Log.w(TAG, "Listen error", e)
                return@addSnapshotListener
            }

            for (change in querySnapshot!!.documentChanges) {
                if (change.type == DocumentChange.Type.ADDED) {
                    Log.d(TAG, "New city: ${change.document.data}")
                }

                val source = if (querySnapshot.metadata.isFromCache)
                    "local cache"
                else
                    "server"
                Log.d(TAG, "Data fetched from $source")
            }
        }

Obtén datos sin conexión

Si intentas obtener un documento mientras el dispositivo no tiene conexión, Firestore muestra datos de la caché.

Cuando se consulta una colección, se muestra un resultado vacío si no hay documentos en la caché. Cuando se intenta recuperar un documento específico, se muestra un error.

Consulta datos sin conexión

La consulta funciona con la persistencia sin conexión. Puedes recuperar los resultados de las consultas con una operación get directa o mediante la escucha, como se describe en las secciones anteriores. También puedes crear nuevas consultas de datos que se conservan en la caché local mientras el dispositivo está sin conexión. Sin embargo, inicialmente, solo se ejecutarán las consultas con los documentos almacenados en caché.

Inhabilita y habilita el acceso a la red

Puedes usar el siguiente método para inhabilitar el acceso de tu cliente de Firestore a la red. Mientras el acceso a la red está inhabilitado, todos los objetos de escucha de instantáneas y las solicitudes de documentos recuperan resultados de la memoria caché. Las operaciones de escritura se ponen en cola hasta que se vuelve a habilitar el acceso a la red.

Web versión 9

import { disableNetwork } from "firebase/firestore";

await disableNetwork(db);
console.log("Network disabled!");
// Do offline actions
// ...

Web versión 8

firebase.firestore().disableNetwork()
    .then(() => {
        // Do offline actions
        // ...
    });
Swift
Nota: Este producto no se encuentra disponible en los destinos de watchOS ni de App Clip.
Firestore.firestore().disableNetwork { (error) in
    // Do offline things
    // ...
}
Objective‑C
Nota: Este producto no está disponible en los destinos de watchOS ni de App Clip.
[[FIRFirestore firestore] disableNetworkWithCompletion:^(NSError *_Nullable error) {
  // Do offline actions
  // ...
}];
Java
Android
db.disableNetwork()
        .addOnCompleteListener(new OnCompleteListener<Void>() {
            @Override
            public void onComplete(@NonNull Task<Void> task) {
                // Do offline things
                // ...
            }
        });
Kotlin+KTX
Android
db.disableNetwork().addOnCompleteListener {
    // Do offline things
    // ...
}

Usa el siguiente método para volver a habilitar el acceso a la red:

Web versión 9

import { enableNetwork } from "firebase/firestore";

await enableNetwork(db);
// Do online actions
// ...

Web versión 8

firebase.firestore().enableNetwork()
    .then(() => {
        // Do online actions
        // ...
    });
Swift
Nota: Este producto no se encuentra disponible en los destinos de watchOS ni de App Clip.
Firestore.firestore().enableNetwork { (error) in
    // Do online things
    // ...
}
Objective‑C
Nota: Este producto no está disponible en los destinos de watchOS ni de App Clip.
[[FIRFirestore firestore] enableNetworkWithCompletion:^(NSError *_Nullable error) {
  // Do online actions
  // ...
}];
Java
Android
db.enableNetwork()
        .addOnCompleteListener(new OnCompleteListener<Void>() {
            @Override
            public void onComplete(@NonNull Task<Void> task) {
                // Do online things
                // ...
            }
        });
Kotlin+KTX
Android
db.enableNetwork().addOnCompleteListener {
    // Do online things
    // ...
}