Cloud Firestore prend en charge la persistance des données hors ligne. Cette fonctionnalité met en cache une copie des données Cloud Firestore que votre application utilise activement, afin que votre application puisse accéder aux données lorsque l'appareil est hors ligne. Vous pouvez écrire, lire, écouter et interroger les données mises en cache. Lorsque l'appareil revient en ligne, Cloud Firestore synchronise toutes les modifications locales apportées par votre application au backend Cloud Firestore.
Pour utiliser la persistance hors ligne, vous n'avez pas besoin de modifier le code que vous utilisez pour accéder aux données Cloud Firestore. Lorsque la persistance hors ligne est activée, la bibliothèque cliente Cloud Firestore gère automatiquement l'accès aux données en ligne et hors ligne et synchronise les données locales lorsque l'appareil est de nouveau en ligne.
Configurer la persistance hors ligne
Lorsque vous initialisez Cloud Firestore, vous pouvez activer ou désactiver la persistance hors connexion :
- Pour les plates-formes Android et Apple, la persistance hors ligne est activée par défaut. Pour désactiver la persistance, définissez l'option
PersistenceEnabled
surfalse
. - Pour le Web, la persistance hors connexion est désactivée par défaut. Pour activer la persistance, appelez la méthode
enablePersistence
. Le cache de Cloud Firestore n'est pas automatiquement effacé entre les sessions. Par conséquent, si votre application Web traite des informations sensibles, assurez-vous de demander à l'utilisateur s'il se trouve sur un appareil de confiance avant d'activer la persistance.
Web modular API
// Memory cache is the default if no config is specified.
initializeFirestore(app);
// This is the default behavior if no persistence is specified.
initializeFirestore(app, {localCache: memoryLocalCache()});
// Defaults to single-tab persistence if no tab manager is specified.
initializeFirestore(app, {localCache: persistentLocalCache(/*settings*/{})});
// Same as `initializeFirestore(app, {localCache: persistentLocalCache(/*settings*/{})})`,
// but more explicit about tab management.
initializeFirestore(app,
{localCache:
persistentLocalCache(/*settings*/{tabManager: persistentSingleTabManager()})
});
// Use multi-tab IndexedDb persistence.
initializeFirestore(app,
{localCache:
persistentLocalCache(/*settings*/{tabManager: persistentMultipleTabManager()})
});
Web namespaced API
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
Rapide
let settings = FirestoreSettings() // Use memory-only cache settings.cacheSettings = MemoryCacheSettings(garbageCollectorSettings: MemoryLRUGCSettings()) // Use persistent disk cache, with 1 MB cache size settings.cacheSettings = PersistentCacheSettings(sizeBytes: 1_000_000) // Any additional options // ... // Enable offline data persistence let db = Firestore.firestore() db.settings = settings
Objectif c
FIRFirestoreSettings *settings = [[FIRFirestoreSettings alloc] init]; // Use memory-only cache settings.cacheSettings = [[FIRMemoryCacheSettings alloc] initWithGarbageCollectorSettings:[[FIRMemoryLRUGCSettings alloc] init]]; // Use persistent disk cache (default behavior) // This example uses 1 million bytes, or 1 MB. settings.cacheSettings = [[FIRPersistentCacheSettings alloc] initWithSizeBytes:@1000000]; // Any additional options // ... // Enable offline data persistence FIRFirestore *db = [FIRFirestore firestore]; db.settings = settings;
Kotlin+KTX
val settings = firestoreSettings { // Use memory cache setLocalCacheSettings(memoryCacheSettings {}) // Use persistent disk cache (default) setLocalCacheSettings(persistentCacheSettings {}) } db.firestoreSettings = settings
Java
FirebaseFirestoreSettings settings = new FirebaseFirestoreSettings.Builder(db.getFirestoreSettings()) // Use memory-only cache .setLocalCacheSettings(MemoryCacheSettings.newBuilder().build()) // Use persistent disk cache (default) .setLocalCacheSettings(PersistentCacheSettings.newBuilder() .build()) .build(); db.setFirestoreSettings(settings);
Dart
// Apple and Android db.settings = const Settings(persistenceEnabled: true); // Web await db .enablePersistence(const PersistenceSettings(synchronizeTabs: true));
Configurer la taille du cache
Lorsque la persistance est activée, Cloud Firestore met en cache chaque document reçu du backend pour un accès hors ligne. Cloud Firestore définit un seuil par défaut pour la taille du cache. Après avoir dépassé la valeur par défaut, Cloud Firestore tente périodiquement de nettoyer les anciens documents inutilisés. Vous pouvez configurer un seuil de taille de cache différent ou désactiver complètement le processus de nettoyage :
Web modular API
import { initializeFirestore, CACHE_SIZE_UNLIMITED } from "firebase/firestore"; const firestoreDb = initializeFirestore(app, { cacheSizeBytes: CACHE_SIZE_UNLIMITED });
Web namespaced API
firebase.firestore().settings({ cacheSizeBytes: firebase.firestore.CACHE_SIZE_UNLIMITED });
Rapide
// 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 // Set cache size to 1 MB settings.cacheSettings = PersistentCacheSettings(sizeBytes: 1_000_000) Firestore.firestore().settings = settings
Objectif c
// 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; // Set cache size to 1 MB settings.cacheSettings = [[FIRPersistentCacheSettings alloc] initWithSizeBytes:@1000000]; [FIRFirestore firestore].settings = settings;
Kotlin+KTX
// 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
Java
// 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);
Dart
db.settings = const Settings( persistenceEnabled: true, cacheSizeBytes: Settings.CACHE_SIZE_UNLIMITED, );
Écouter des données hors ligne
Lorsque l'appareil est hors ligne, si vous avez activé la persistance hors ligne, vos auditeurs recevront des événements d'écoute lorsque les données mises en cache localement changeront. Vous pouvez écouter des documents, des collections et des requêtes.
Pour vérifier si vous recevez des données du serveur ou du cache, utilisez la propriété fromCache
sur SnapshotMetadata
dans votre événement d'instantané. Si fromCache
est true
, les données proviennent du cache et peuvent être obsolètes ou incomplètes. Si fromCache
est false
, les données sont complètes et à jour avec les dernières mises à jour sur le serveur.
Par défaut, aucun événement n'est déclenché si seul le SnapshotMetadata
a changé. Si vous comptez sur les valeurs fromCache
, spécifiez l'option d'écoute includeMetadataChanges
lorsque vous attachez votre gestionnaire d'écoute.
Web modular API
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 namespaced API
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); }); });
Rapide
// 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)") }
Objectif c
// 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); }];
Kotlin+KTX
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") } }
Java
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); } } });
Dart
db .collection("cities") .where("state", isEqualTo: "CA") .snapshots(includeMetadataChanges: true) .listen((querySnapshot) { for (var change in querySnapshot.docChanges) { if (change.type == DocumentChangeType.added) { final source = (querySnapshot.metadata.isFromCache) ? "local cache" : "server"; print("Data fetched from $source}"); } } });
Obtenir des données hors ligne
Si vous obtenez un document alors que l'appareil est hors ligne, Cloud Firestore renvoie les données du cache.
Lors de l'interrogation d'une collection, un résultat vide est renvoyé s'il n'y a pas de documents en cache. Lors de la récupération d'un document spécifique, une erreur est renvoyée à la place.
Interroger des données hors ligne
L'interrogation fonctionne avec la persistance hors ligne. Vous pouvez récupérer les résultats des requêtes avec une extraction directe ou en écoutant, comme décrit dans les sections précédentes. Vous pouvez également créer de nouvelles requêtes sur des données persistantes localement lorsque l'appareil est hors ligne, mais les requêtes ne s'exécuteront initialement que sur les documents mis en cache.
Configurer les index de requête hors ligne
Par défaut, le SDK Firestore analyse tous les documents d'une collection dans son cache local lors de l'exécution de requêtes hors ligne. Avec ce comportement par défaut, les performances des requêtes hors ligne peuvent être affectées lorsque les utilisateurs sont hors ligne pendant de longues périodes.
Vous pouvez améliorer les performances des requêtes hors connexion en configurant des index de requête locaux :
Rapide
Le SDK de la plate-forme Apple fournit une méthode setIndexConfiguration
qui lit la même configuration structurée JSON utilisée pour configurer les index sur le serveur, en suivant le même format de définition d'index .
// You will normally read this from a file asset or cloud storage. let indexConfigJson = """ { indexes: [ ... ], fieldOverrides: [ ... ] } """ // Apply the configuration. Firestore.firestore().setIndexConfiguration(indexConfigJson)
Objectif c
Le SDK de la plate-forme Apple fournit setIndexConfiguration
- des méthodes qui lisent la même configuration structurée JSON utilisée pour configurer les index sur le serveur, en suivant le même format de définition d'index .
// You will normally read this from a file asset or cloud storage. NSString *indexConfigJson = @" { " " indexes: [ " " ... " " ], " " fieldOverrides: [ " " ... " " ] " " } "; // Apply the configuration. [[FIRFirestore firestore] setIndexConfigurationFromJSON:indexConfigJson completion:^(NSError * _Nullable error) { // ... }];
Java
Le SDK Android fournit une méthode setIndexConfiguration
qui lit la même configuration structurée JSON utilisée pour configurer les index sur le serveur, en suivant le même format de définition d'index .
// You will normally read this from a file asset or cloud storage. String indexConfigJson = " { " + " indexes: [ " + " ... " + " ], " + " fieldOverrides: [ " + " ... " + " ] " + " } "; // Apply the configuration. FirebaseFirestore.getInstance().setIndexConfiguration(indexConfigJson);
Kotlin+KTX
Le SDK Android fournit une méthode setIndexConfiguration
qui lit la même configuration structurée JSON utilisée pour configurer les index sur le serveur, en suivant le même format de définition d'index .
// You will normally read this from a file asset or cloud storage. val indexConfigJson = """ { indexes: [ ... ], fieldOverrides: [ ... ] } """ // Apply the configuration. FirebaseFirestore.getInstance().setIndexConfiguration(indexConfigJson)
Dart
Le SDK Flutter fournit une méthode setIndexConfigurationFromJSON
qui lit la même configuration structurée JSON utilisée pour configurer les index sur le serveur, en suivant le même format de définition d'index .
// You will normally read this from a file asset or cloud storage. var indexConfigJson = """ { indexes: [ ... ], fieldOverrides: [ ... ] } """; // Apply the configuration. await FirebaseFirestore.instance.setIndexConfigurationFromJSON(json: indexConfigJson);
Vous pouvez également utiliser la méthode setIndexConfiguration
pour configurer les index avec une API basée sur les classes.
var indexes = [ Index( collectionGroup: "posts", queryScope: QueryScope.collection, fields: [ IndexField(fieldPath: "author", arrayConfig: ArrayConfig.contains), IndexField(fieldPath: "timestamp", order: Order.descending) ], ), ]; await FirebaseFirestore.instance.setIndexConfiguration(indexes: indexes);
La configuration d'index hors ligne à utiliser dépend des collections et des documents auxquels votre application accède fortement en mode hors connexion et des performances hors ligne souhaitées. Bien que vous puissiez exporter votre configuration d'index backend pour une utilisation sur le client, les modèles d'accès hors ligne de votre application diffèrent probablement considérablement des modèles d'accès en ligne, de sorte que votre configuration d'index en ligne peut ne pas convenir à une utilisation hors ligne. À quelles collections et documents souhaitez-vous que votre application accède hors ligne avec des performances élevées ? Une fois que vous avez analysé le comportement de votre application, suivez les principes de définition d'index du guide d'indexation .
Pour rendre les configurations d'index hors ligne disponibles pour le chargement dans votre application client :
- compilez-les et distribuez-les avec votre application
- les télécharger depuis un CDN
- récupérez-les à partir d'un système de stockage tel que Cloud Storage pour Firebase .
Désactiver et activer l'accès au réseau
Vous pouvez utiliser la méthode ci-dessous pour désactiver l'accès au réseau pour votre client Cloud Firestore. Lorsque l'accès au réseau est désactivé, tous les écouteurs d'instantanés et les demandes de documents récupèrent les résultats du cache. Les opérations d'écriture sont mises en file d'attente jusqu'à ce que l'accès au réseau soit réactivé.
Web modular API
import { disableNetwork } from "firebase/firestore"; await disableNetwork(db); console.log("Network disabled!"); // Do offline actions // ...
Web namespaced API
firebase.firestore().disableNetwork() .then(() => { // Do offline actions // ... });
Rapide
Firestore.firestore().disableNetwork { (error) in // Do offline things // ... }
Objectif c
[[FIRFirestore firestore] disableNetworkWithCompletion:^(NSError *_Nullable error) { // Do offline actions // ... }];
Kotlin+KTX
db.disableNetwork().addOnCompleteListener { // Do offline things // ... }
Java
db.disableNetwork() .addOnCompleteListener(new OnCompleteListener<Void>() { @Override public void onComplete(@NonNull Task<Void> task) { // Do offline things // ... } });
Dart
db.disableNetwork().then((_) { // Do offline things });
Utilisez la méthode suivante pour réactiver l'accès au réseau :
Web modular API
import { enableNetwork } from "firebase/firestore"; await enableNetwork(db); // Do online actions // ...
Web namespaced API
firebase.firestore().enableNetwork() .then(() => { // Do online actions // ... });
Rapide
Firestore.firestore().enableNetwork { (error) in // Do online things // ... }
Objectif c
[[FIRFirestore firestore] enableNetworkWithCompletion:^(NSError *_Nullable error) { // Do online actions // ... }];
Kotlin+KTX
db.enableNetwork().addOnCompleteListener { // Do online things // ... }
Java
db.enableNetwork() .addOnCompleteListener(new OnCompleteListener<Void>() { @Override public void onComplete(@NonNull Task<Void> task) { // Do online things // ... } });
Dart
db.enableNetwork().then((_) { // Back online });