Activer les données hors connexion
Firestore est compatible avec la persistance des données hors connexion. Cette fonctionnalité met en cache une copie des données Firestore utilisées activement par votre application, afin que votre application puisse accéder aux données lorsque l'appareil est hors connexion. Vous pouvez écrire, lire, écouter et interroger les données mises en cache. Lorsque l'appareil est de nouveau en ligne, Firestore synchronise toutes les modifications locales apportées par votre application au backend Firestore.
Pour utiliser la persistance hors connexion, vous n'avez pas besoin d'apporter de modifications au code que vous utilisez pour accéder aux données Firestore. Si la persistance hors connexion est activée, la bibliothèque cliente de Firestore gère automatiquement l'accès aux données en ligne et hors connexion, et synchronise les données locales lorsque l'appareil est de nouveau connecté.
Configurer la persistance hors connexion
Lorsque vous initialisez Firestore, vous pouvez activer ou désactiver la persistance hors connexion :
- Pour les plates-formes Android et Apple, la persistance hors connexion 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 Firestore n'est pas automatiquement vidé entre les sessions. Par conséquent, si votre application Web traite des informations sensibles, demandez à l'utilisateur s'il utilise un appareil fiable avant d'activer la persistance
Version Web 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
Version Web 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
let settings = FirestoreSettings() settings.isPersistenceEnabled = true // Any additional options // ... // Enable offline data persistence let db = Firestore.firestore() db.settings = settings
Objective-C
FIRFirestoreSettings *settings = [[FIRFirestoreSettings alloc] init]; settings.persistenceEnabled = YES; // Any additional options // ... // Enable offline data persistence FIRFirestore *db = [FIRFirestore firestore]; db.settings = settings;
Kotlin + KTX
Android
val settings = firestoreSettings { isPersistenceEnabled = true } db.firestoreSettings = settings
Java
Android
FirebaseFirestoreSettings settings = new FirebaseFirestoreSettings.Builder() .setPersistenceEnabled(true) .build(); db.setFirestoreSettings(settings);
Fléchette
// 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, Firestore met en cache tous les documents reçus du backend pour un accès hors connexion. Firestore définit un seuil par défaut pour la taille du cache. Une fois la valeur par défaut dépassée, Firestore tente régulièrement de nettoyer les documents inutilisés. Vous pouvez configurer un autre seuil pour la taille du cache ou désactiver complètement le processus de nettoyage :
Version Web 9
import { initializeFirestore, CACHE_SIZE_UNLIMITED } from "firebase/firestore"; const firestoreDb = initializeFirestore(app, { cacheSizeBytes: CACHE_SIZE_UNLIMITED });
Version Web 8
firebase.firestore().settings({ cacheSizeBytes: firebase.firestore.CACHE_SIZE_UNLIMITED });
Swift
// 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
// 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;
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
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);
Fléchette
db.settings = const Settings( persistenceEnabled: true, cacheSizeBytes: Settings.CACHE_SIZE_UNLIMITED, );
Écouter des données hors connexion
Lorsque l'appareil est hors connexion, si vous avez activé la persistance hors connexion, vos écouteurs reçoivent des événements d'écoute lorsque les données mises en cache localement sont modifiées. 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
du SnapshotMetadata
de votre événement instantané. Si fromCache
correspond à true
, les données proviennent du cache et peuvent être obsolètes ou incomplètes. Si fromCache
correspond à false
, les données sont complètes et actualisées avec les dernières mises à jour sur le serveur.
Par défaut, aucun événement n'est déclenché si seulement le SnapshotMetadata
a été modifié. Si vous utilisez les valeurs fromCache
, spécifiez l'option d'écoute includeMetadataChanges
lorsque vous associez votre gestionnaire d'écoute.
Version Web 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); }); });
Version Web 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
// 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
// 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
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") } }
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); } } });
Fléchette
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 connexion
Si vous recevez un document alors que l'appareil est hors connexion, Firestore renvoie les données du cache.
Lorsque vous interrogez une collection, un résultat vide est renvoyé si elle ne contient pas de documents mis en cache. Si vous essayez de récupérer un document spécifique, une erreur est renvoyée.
Interroger les données hors connexion
L'interrogation fonctionne avec la persistance hors connexion. Vous pouvez récupérer les résultats des requêtes à travers un accès direct 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 conservées localement lorsque l'appareil est hors connexion, mais les requêtes ne seront exécutées que sur les documents mis en cache.
Configurer des index de requête hors connexion
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 connexion. Ce comportement par défaut peut nuire aux performances des requêtes hors connexion lorsque les utilisateurs sont hors connexion pendant de longues périodes.
Vous pouvez améliorer les performances des requêtes hors connexion en configurant des index de requête locaux:
Swift
Le SDK de la plate-forme Apple fournit une méthode setIndexConfiguration
qui lit la même configuration structurée au format JSON que celle utilisée pour configurer les index sur le serveur, selon 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)
Objective-C
Le SDK de la plate-forme Apple fournit des méthodes setIndexConfiguration
- qui lisent la même configuration structurée au format JSON que celle utilisée pour configurer les index sur le serveur, selon 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
Android
Le SDK Android fournit une méthode setIndexConfiguration
qui lit la même configuration structurée au format JSON que celle utilisée pour configurer les index sur le serveur, selon 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
Android
Le SDK Android fournit une méthode setIndexConfiguration
qui lit la même configuration structurée au format JSON que celle utilisée pour configurer les index sur le serveur, selon 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)
Fléchette
Le SDK Flutter fournit une méthode setIndexConfigurationFromJSON
qui lit la même configuration structurée au format JSON que celle utilisée pour configurer les index sur le serveur, selon 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 des index avec une API basée sur des 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 connexion à utiliser dépend des collections et des documents auxquels votre application accède beaucoup hors connexion, ainsi que des performances hors connexion souhaitées. Bien que vous puissiez exporter la configuration de votre index backend pour l'utiliser sur le client, les modèles d'accès hors connexion de votre application diffèrent probablement considérablement des modèles d'accès en ligne. Par conséquent, votre configuration d'index en ligne peut ne pas être adaptée à une utilisation hors connexion. Quels documents et collections souhaitez-vous que votre application accède hors connexion avec de hautes performances ? 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 connexion disponibles pour le chargement dans votre application cliente:
- de les compiler et de les distribuer avec votre application
- les télécharger depuis un CDN
- Vous pouvez les récupérer depuis un système de stockage tel que Cloud Storage.
Désactiver et activer l'accès au réseau
Vous pouvez utiliser la méthode ci-dessous pour désactiver l'accès réseau de votre client Firestore. Lorsque l'accès au réseau est désactivé, tous les écouteurs d'instantanés et les requêtes de documents récupèrent les résultats à partir du cache. Les opérations d'écriture sont mises en attente jusqu'à ce que l'accès au réseau soit réactivé..
Version Web 9
import { disableNetwork } from "firebase/firestore"; await disableNetwork(db); console.log("Network disabled!"); // Do offline actions // ...
Version Web 8
firebase.firestore().disableNetwork() .then(() => { // Do offline actions // ... });
Swift
Firestore.firestore().disableNetwork { (error) in // Do offline things // ... }
Objective-C
[[FIRFirestore firestore] disableNetworkWithCompletion:^(NSError *_Nullable error) { // Do offline actions // ... }];
Kotlin + KTX
Android
db.disableNetwork().addOnCompleteListener { // Do offline things // ... }
Java
Android
db.disableNetwork() .addOnCompleteListener(new OnCompleteListener<Void>() { @Override public void onComplete(@NonNull Task<Void> task) { // Do offline things // ... } });
Fléchette
db.disableNetwork().then((_) { // Do offline things });
Pour réactiver l'accès au réseau, procédez comme suit :
Version Web 9
import { enableNetwork } from "firebase/firestore"; await enableNetwork(db); // Do online actions // ...
Version Web 8
firebase.firestore().enableNetwork() .then(() => { // Do online actions // ... });
Swift
Firestore.firestore().enableNetwork { (error) in // Do online things // ... }
Objective-C
[[FIRFirestore firestore] enableNetworkWithCompletion:^(NSError *_Nullable error) { // Do online actions // ... }];
Kotlin + KTX
Android
db.enableNetwork().addOnCompleteListener { // Do online things // ... }
Java
Android
db.enableNetwork() .addOnCompleteListener(new OnCompleteListener<Void>() { @Override public void onComplete(@NonNull Task<Void> task) { // Do online things // ... } });
Fléchette
db.enableNetwork().then((_) { // Back online });