Cloud Firestore 支持離線數據持久化。此功能會緩存您的應用正在使用的 Cloud Firestore 數據的副本,以便您的應用可以在設備離線時訪問數據。您可以寫入、讀取、偵聽和查詢緩存的數據。當設備重新上線時,Cloud Firestore 會將您的應用所做的任何本地更改同步到 Cloud Firestore 後端。
要使用離線持久性,您無需對用於訪問 Cloud Firestore 數據的代碼進行任何更改。啟用離線持久性後,Cloud Firestore 客戶端庫會自動管理在線和離線數據訪問,並在設備重新在線時同步本地數據。
配置離線持久化
初始化 Cloud Firestore 時,您可以啟用或禁用離線持久性:
- 對於 Android 和 Apple 平台,默認啟用離線持久性。要禁用持久性,請將
PersistenceEnabled
選項設置為false
。 - 對於 Web,默認情況下禁用離線持久性。要啟用持久性,請調用
enablePersistence
方法。 Cloud Firestore 的緩存不會在會話之間自動清除。因此,如果您的 Web 應用程序處理敏感信息,請確保在啟用持久性之前詢問用戶他們是否在受信任的設備上。
Web version 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 version 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
迅速
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;
Java
FirebaseFirestoreSettings settings = new FirebaseFirestoreSettings.Builder() .setPersistenceEnabled(true) .build(); db.setFirestoreSettings(settings);
Kotlin+KTX
val settings = firestoreSettings { isPersistenceEnabled = true } db.firestoreSettings = settings
Dart
// Apple and Android db.settings = const Settings(persistenceEnabled: true); // Web await db .enablePersistence(const PersistenceSettings(synchronizeTabs: true));
配置緩存大小
啟用持久性後,Cloud Firestore 會緩存從後端接收到的每個文檔以供離線訪問。 Cloud Firestore 設置了緩存大小的默認閾值。超過默認值後,Cloud Firestore 會定期嘗試清理舊的、未使用的文檔。您可以配置不同的緩存大小閾值或完全禁用清理過程:
Web version 9
import { initializeFirestore, CACHE_SIZE_UNLIMITED } from "firebase/firestore"; const firestoreDb = initializeFirestore(app, { cacheSizeBytes: CACHE_SIZE_UNLIMITED });
Web version 8
firebase.firestore().settings({ cacheSizeBytes: firebase.firestore.CACHE_SIZE_UNLIMITED });
迅速
// 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;
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);
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
Dart
db.settings = const Settings( persistenceEnabled: true, cacheSizeBytes: Settings.CACHE_SIZE_UNLIMITED, );
收聽離線數據
當設備離線時,如果你啟用了離線持久化,當本地緩存的數據發生變化時,你的監聽器會收到監聽事件。您可以收聽文檔、集合和查詢。
要檢查您是從服務器接收數據還是從緩存接收數據,請在快照事件中使用SnapshotMetadata
上的fromCache
屬性。如果fromCache
為true
,則數據來自緩存並且可能是陳舊的或不完整的。如果fromCache
為false
,則數據是完整的並且是服務器上最新更新的最新數據。
默認情況下,如果僅SnapshotMetadata
發生更改,則不會引發任何事件。如果您依賴fromCache
值,請在附加偵聽處理程序時指定includeMetadataChanges
偵聽選項。
Web version 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 version 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); }); });
迅速
// 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); }];
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); } } });
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") } }
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}"); } } });
獲取離線數據
如果您在設備離線時獲取文檔,Cloud Firestore 會從緩存中返回數據。
查詢集合時,如果沒有緩存文檔,則返回空結果。獲取特定文檔時,會返回錯誤。
查詢離線數據
查詢與離線持久性一起工作。您可以使用直接獲取或通過偵聽來檢索查詢結果,如前面部分所述。您還可以在設備離線時對本地持久數據創建新查詢,但查詢最初將僅針對緩存的文檔運行。
禁用和啟用網絡訪問
您可以使用以下方法禁用 Cloud Firestore 客戶端的網絡訪問。在禁用網絡訪問時,所有快照偵聽器和文檔請求都會從緩存中檢索結果。寫入操作會排隊,直到重新啟用網絡訪問。
Web version 9
import { disableNetwork } from "firebase/firestore"; await disableNetwork(db); console.log("Network disabled!"); // Do offline actions // ...
Web version 8
firebase.firestore().disableNetwork() .then(() => { // Do offline actions // ... });
迅速
Firestore.firestore().disableNetwork { (error) in // Do offline things // ... }
Objective-C
[[FIRFirestore firestore] disableNetworkWithCompletion:^(NSError *_Nullable error) { // Do offline actions // ... }];
Java
db.disableNetwork() .addOnCompleteListener(new OnCompleteListener<Void>() { @Override public void onComplete(@NonNull Task<Void> task) { // Do offline things // ... } });
Kotlin+KTX
db.disableNetwork().addOnCompleteListener { // Do offline things // ... }
Dart
db.disableNetwork().then((_) { // Do offline things });
使用以下方法重新啟用網絡訪問:
Web version 9
import { enableNetwork } from "firebase/firestore"; await enableNetwork(db); // Do online actions // ...
Web version 8
firebase.firestore().enableNetwork() .then(() => { // Do online actions // ... });
迅速
Firestore.firestore().enableNetwork { (error) in // Do online things // ... }
Objective-C
[[FIRFirestore firestore] enableNetworkWithCompletion:^(NSError *_Nullable error) { // Do online actions // ... }];
Java
db.enableNetwork() .addOnCompleteListener(new OnCompleteListener<Void>() { @Override public void onComplete(@NonNull Task<Void> task) { // Do online things // ... } });
Kotlin+KTX
db.enableNetwork().addOnCompleteListener { // Do online things // ... }
Dart
db.enableNetwork().then((_) { // Back online });
Cloud Firestore 支持離線數據持久化。此功能會緩存您的應用正在使用的 Cloud Firestore 數據的副本,以便您的應用可以在設備離線時訪問數據。您可以寫入、讀取、偵聽和查詢緩存的數據。當設備重新上線時,Cloud Firestore 會將您的應用所做的任何本地更改同步到 Cloud Firestore 後端。
要使用離線持久性,您無需對用於訪問 Cloud Firestore 數據的代碼進行任何更改。啟用離線持久性後,Cloud Firestore 客戶端庫會自動管理在線和離線數據訪問,並在設備重新在線時同步本地數據。
配置離線持久化
初始化 Cloud Firestore 時,您可以啟用或禁用離線持久性:
- 對於 Android 和 Apple 平台,默認啟用離線持久性。要禁用持久性,請將
PersistenceEnabled
選項設置為false
。 - 對於 Web,默認情況下禁用離線持久性。要啟用持久性,請調用
enablePersistence
方法。 Cloud Firestore 的緩存不會在會話之間自動清除。因此,如果您的 Web 應用程序處理敏感信息,請確保在啟用持久性之前詢問用戶他們是否在受信任的設備上。
Web version 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 version 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
迅速
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;
Java
FirebaseFirestoreSettings settings = new FirebaseFirestoreSettings.Builder() .setPersistenceEnabled(true) .build(); db.setFirestoreSettings(settings);
Kotlin+KTX
val settings = firestoreSettings { isPersistenceEnabled = true } db.firestoreSettings = settings
Dart
// Apple and Android db.settings = const Settings(persistenceEnabled: true); // Web await db .enablePersistence(const PersistenceSettings(synchronizeTabs: true));
配置緩存大小
啟用持久性後,Cloud Firestore 會緩存從後端接收到的每個文檔以供離線訪問。 Cloud Firestore 設置了緩存大小的默認閾值。超過默認值後,Cloud Firestore 會定期嘗試清理舊的、未使用的文檔。您可以配置不同的緩存大小閾值或完全禁用清理過程:
Web version 9
import { initializeFirestore, CACHE_SIZE_UNLIMITED } from "firebase/firestore"; const firestoreDb = initializeFirestore(app, { cacheSizeBytes: CACHE_SIZE_UNLIMITED });
Web version 8
firebase.firestore().settings({ cacheSizeBytes: firebase.firestore.CACHE_SIZE_UNLIMITED });
迅速
// 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;
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);
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
Dart
db.settings = const Settings( persistenceEnabled: true, cacheSizeBytes: Settings.CACHE_SIZE_UNLIMITED, );
收聽離線數據
當設備離線時,如果你啟用了離線持久化,當本地緩存的數據發生變化時,你的監聽器會收到監聽事件。您可以收聽文檔、集合和查詢。
要檢查您是從服務器接收數據還是從緩存接收數據,請在快照事件中使用SnapshotMetadata
上的fromCache
屬性。如果fromCache
為true
,則數據來自緩存並且可能是陳舊的或不完整的。如果fromCache
為false
,則數據是完整的並且是服務器上最新更新的最新數據。
默認情況下,如果僅SnapshotMetadata
發生更改,則不會引發任何事件。如果您依賴fromCache
值,請在附加偵聽處理程序時指定includeMetadataChanges
偵聽選項。
Web version 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 version 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); }); });
迅速
// 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); }];
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); } } });
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") } }
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}"); } } });
獲取離線數據
如果您在設備離線時獲取文檔,Cloud Firestore 會從緩存中返回數據。
查詢集合時,如果沒有緩存文檔,則返回空結果。獲取特定文檔時,會返回錯誤。
查詢離線數據
查詢與離線持久性一起工作。您可以使用直接獲取或通過偵聽來檢索查詢結果,如前面部分所述。您還可以在設備離線時對本地持久數據創建新查詢,但查詢最初將僅針對緩存的文檔運行。
禁用和啟用網絡訪問
您可以使用以下方法禁用 Cloud Firestore 客戶端的網絡訪問。在禁用網絡訪問時,所有快照偵聽器和文檔請求都會從緩存中檢索結果。寫入操作會排隊,直到重新啟用網絡訪問。
Web version 9
import { disableNetwork } from "firebase/firestore"; await disableNetwork(db); console.log("Network disabled!"); // Do offline actions // ...
Web version 8
firebase.firestore().disableNetwork() .then(() => { // Do offline actions // ... });
迅速
Firestore.firestore().disableNetwork { (error) in // Do offline things // ... }
Objective-C
[[FIRFirestore firestore] disableNetworkWithCompletion:^(NSError *_Nullable error) { // Do offline actions // ... }];
Java
db.disableNetwork() .addOnCompleteListener(new OnCompleteListener<Void>() { @Override public void onComplete(@NonNull Task<Void> task) { // Do offline things // ... } });
Kotlin+KTX
db.disableNetwork().addOnCompleteListener { // Do offline things // ... }
Dart
db.disableNetwork().then((_) { // Do offline things });
使用以下方法重新啟用網絡訪問:
Web version 9
import { enableNetwork } from "firebase/firestore"; await enableNetwork(db); // Do online actions // ...
Web version 8
firebase.firestore().enableNetwork() .then(() => { // Do online actions // ... });
迅速
Firestore.firestore().enableNetwork { (error) in // Do online things // ... }
Objective-C
[[FIRFirestore firestore] enableNetworkWithCompletion:^(NSError *_Nullable error) { // Do online actions // ... }];
Java
db.enableNetwork() .addOnCompleteListener(new OnCompleteListener<Void>() { @Override public void onComplete(@NonNull Task<Void> task) { // Do online things // ... } });
Kotlin+KTX
db.enableNetwork().addOnCompleteListener { // Do online things // ... }
Dart
db.enableNetwork().then((_) { // Back online });