เข้าถึงข้อมูลแบบออฟไลน์

Cloud Firestore รองรับความต่อเนื่องของข้อมูลแบบออฟไลน์ ฟีเจอร์นี้จะแคชสำเนาข้อมูล Cloud Firestore ที่แอปของคุณใช้อยู่ เพื่อให้แอปเข้าถึงข้อมูลได้เมื่ออุปกรณ์ออฟไลน์ คุณสามารถเขียน อ่าน ฟัง และค้นหาข้อมูลที่แคชไว้ได้ เมื่ออุปกรณ์กลับมาออนไลน์อีกครั้ง Cloud Firestore จะซิงค์การเปลี่ยนแปลงในแอปที่เกิดขึ้นในเครื่องกับแบ็กเอนด์ Cloud Firestore

หากต้องการใช้การคงข้อมูลไว้แบบออฟไลน์ คุณไม่จําเป็นต้องเปลี่ยนแปลงโค้ดที่ใช้เข้าถึงข้อมูล Cloud Firestore เมื่อเปิดใช้การเก็บข้อมูลแบบออฟไลน์ ไลบรารีไคลเอ็นต์ Cloud Firestore จะจัดการการเข้าถึงข้อมูลออนไลน์และออฟไลน์โดยอัตโนมัติ และซิงค์ข้อมูลในเครื่องเมื่ออุปกรณ์กลับมาออนไลน์อีกครั้ง

กำหนดค่าความต่อเนื่องแบบออฟไลน์

เมื่อเริ่มต้น Cloud Firestore คุณจะเปิดหรือปิดใช้การเก็บข้อมูลแบบออฟไลน์ได้ ดังนี้

  • สำหรับแพลตฟอร์ม Android และ Apple ระบบจะเปิดใช้การเก็บข้อมูลไว้ใช้แบบออฟไลน์โดยค่าเริ่มต้น หากต้องการปิดใช้การคงสถานะ ให้ตั้งค่าตัวเลือก PersistenceEnabled เป็น false
  • สำหรับเว็บ ระบบจะปิดใช้สถานะคงที่แบบออฟไลน์ไว้โดยค่าเริ่มต้น หากต้องการเปิดใช้การเก็บรักษา ให้เรียกใช้เมธอด enablePersistence ระบบจะไม่ล้างแคชของ Cloud Firestore ระหว่างเซสชันโดยอัตโนมัติ ดังนั้น หากเว็บแอปของคุณจัดการข้อมูลที่ละเอียดอ่อน โปรดตรวจสอบว่าผู้ใช้ใช้อุปกรณ์ที่เชื่อถือได้ก่อนที่จะเปิดใช้การคงสถานะ

Web

// 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

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
หมายเหตุ: ผลิตภัณฑ์นี้ไม่พร้อมใช้งานบนเป้าหมาย watchOS และ App Clip
let settings = FirestoreSettings()

// Use memory-only cache
settings.cacheSettings =
MemoryCacheSettings(garbageCollectorSettings: MemoryLRUGCSettings())

// Use persistent disk cache, with 100 MB cache size
settings.cacheSettings = PersistentCacheSettings(sizeBytes: 100 * 1024 * 1024 as NSNumber)

// Any additional options
// ...

// Enable offline data persistence
let db = Firestore.firestore()
db.settings = settings
Objective-C
หมายเหตุ: ผลิตภัณฑ์นี้ไม่พร้อมใช้งานบนเป้าหมาย watchOS และ App Clip
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 100 MB.
settings.cacheSettings = [[FIRPersistentCacheSettings alloc]
    initWithSizeBytes:@(100 * 1024 * 1024)];

// 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));

กำหนดค่าขนาดแคช

เมื่อเปิดใช้การถาวร Cloud Firestore จะแคชเอกสารทั้งหมดที่ได้รับจากแบ็กเอนด์เพื่อเข้าถึงแบบออฟไลน์ Cloud Firestore จะกำหนดเกณฑ์เริ่มต้นสำหรับขนาดแคช หลังจากเกินค่าเริ่มต้น Cloud Firestore จะพยายามล้างเอกสารเก่าที่ไม่ได้ใช้เป็นระยะๆ คุณสามารถกําหนดค่าเกณฑ์ขนาดแคชอื่นหรือปิดใช้กระบวนการล้างข้อมูลโดยสมบูรณ์ได้ ดังนี้

Web

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

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

Web

firebase.firestore().settings({
    cacheSizeBytes: firebase.firestore.CACHE_SIZE_UNLIMITED
});
Swift
หมายเหตุ: ผลิตภัณฑ์นี้ไม่พร้อมใช้งานบนเป้าหมาย watchOS และ 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
// Set cache size to 100 MB
settings.cacheSettings = PersistentCacheSettings(sizeBytes: 100 * 1024 * 1024 as NSNumber)
Firestore.firestore().settings = settings
Objective-C
หมายเหตุ: ผลิตภัณฑ์นี้ใช้ไม่ได้กับเป้าหมาย WatchOS และ 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;
// Set cache size to 100 MB
settings.cacheSettings =
    [[FIRPersistentCacheSettings alloc] initWithSizeBytes:@(100 * 1024 * 1024)];
[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,
);

ฟังข้อมูลแบบออฟไลน์

ขณะที่อุปกรณ์ออฟไลน์อยู่ หากคุณเปิดใช้การเก็บข้อมูลแบบออฟไลน์ ผู้ฟังจะได้รับเหตุการณ์การฟังเมื่อข้อมูลในแคชในเครื่องมีการเปลี่ยนแปลง คุณสามารถฟังเอกสาร คอลเล็กชัน และการค้นหาได้

หากต้องการตรวจสอบว่าคุณได้รับข้อมูลจากเซิร์ฟเวอร์หรือแคช ให้ใช้พร็อพเพอร์ตี้ fromCache ใน SnapshotMetadata ในเหตุการณ์ภาพรวม หาก fromCache เป็น true แสดงว่าข้อมูลมาจากแคชและอาจล้าสมัยหรือไม่สมบูรณ์ หาก fromCache เป็น false แสดงว่าข้อมูลสมบูรณ์และเป็นข้อมูลล่าสุดตามการอัปเดตล่าสุดในเซิร์ฟเวอร์

โดยค่าเริ่มต้น ระบบจะไม่แสดงเหตุการณ์หากมีการเปลี่ยนแปลงSnapshotMetadataเท่านั้น หากคุณใช้ค่า fromCache ให้ระบุตัวเลือกการฟัง includeMetadataChanges เมื่อแนบตัวแฮนเดิลการฟัง

Web

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

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
หมายเหตุ: ผลิตภัณฑ์นี้ไม่พร้อมใช้งานบนเป้าหมาย watchOS และ 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
หมายเหตุ: ผลิตภัณฑ์นี้ไม่พร้อมใช้งานบนเป้าหมาย watchOS และ 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);
    }];

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}");
    }
  }
});

รับข้อมูลออฟไลน์

หากคุณได้รับเอกสารขณะที่อุปกรณ์ออฟไลน์อยู่ Cloud Firestore จะแสดงข้อมูลจากแคช

เมื่อค้นหาคอลเล็กชัน ระบบจะแสดงผลลัพธ์ว่างเปล่าหากไม่มีเอกสารที่แคชไว้ เมื่อดึงข้อมูลเอกสารบางรายการ ระบบจะแสดงข้อผิดพลาดแทน

ค้นหาข้อมูลออฟไลน์

การค้นหาจะทำงานร่วมกับการเก็บรักษาแบบออฟไลน์ คุณสามารถเรียกข้อมูลผลการค้นหาได้ด้วยการเรียกข้อมูลโดยตรงหรือการฟังตามที่อธิบายไว้ในส่วนก่อนหน้า นอกจากนี้ คุณยังสร้างการค้นหาใหม่ในข้อมูลที่เก็บไว้ในพื้นที่ได้ขณะที่อุปกรณ์ออฟไลน์ แต่การค้นหาจะทํางานกับเอกสารที่แคชไว้เท่านั้นในตอนแรก

กำหนดค่าดัชนีการค้นหาแบบออฟไลน์

โดยค่าเริ่มต้น Firestore SDK จะสแกนเอกสารทั้งหมดในคอลเล็กชันในแคชในเครื่องเมื่อทำการค้นหาแบบออฟไลน์ ลักษณะการทำงานเริ่มต้นนี้อาจทำให้ประสิทธิภาพของการค้นหาออฟไลน์ลดลงเมื่อผู้ใช้ออฟไลน์เป็นเวลานาน

เมื่อเปิดใช้แคชถาวร คุณจะปรับปรุงประสิทธิภาพของการค้นหาแบบออฟไลน์ได้โดยอนุญาตให้ SDK สร้างดัชนีการค้นหาในเครื่องโดยอัตโนมัติ

ระบบจะปิดใช้การจัดทําดัชนีอัตโนมัติโดยค่าเริ่มต้น แอปของคุณต้องเปิดใช้การจัดทำดัชนีอัตโนมัติทุกครั้งที่เริ่มต้น ควบคุมว่าจะเปิดใช้การจัดทำดัชนีอัตโนมัติหรือไม่ ดังที่แสดงด้านล่าง

Swift
if let indexManager = Firestore.firestore().persistentCacheIndexManager {
  // Indexing is disabled by default
  indexManager.enableIndexAutoCreation()
} else {
  print("indexManager is nil")
}
    
Objective-C
PersistentCacheIndexManager *indexManager = [FIRFirestore firestore].persistentCacheIndexManager;
if (indexManager) {
  // Indexing is disabled by default
  [indexManager enableIndexAutoCreation];
}
    

Kotlin+KTX

// return type: PersistentCacheManager?

Firebase.firestore.persistentCacheIndexManager?.apply {
      // Indexing is disabled by default
      enableIndexAutoCreation()
    } ?: println("indexManager is null")
    

Java

// return type: @Nullable PersistentCacheIndexManager
PersistentCacheIndexManager indexManager = FirebaseFirestore.getInstance().getPersistentCacheIndexManager();
if (indexManager != null) {
  // Indexing is disabled by default
  indexManager.enableIndexAutoCreation();
}

// If not check indexManager != null, IDE shows warning: Method invocation 'enableIndexAutoCreation' may produce 'NullPointerException' 
FirebaseFirestore.getInstance().getPersistentCacheIndexManager().enableIndexAutoCreation();
    

เมื่อเปิดใช้การจัดทำดัชนีอัตโนมัติแล้ว SDK จะประเมินคอลเล็กชันที่มีเอกสารที่แคชไว้จำนวนมาก และเพิ่มประสิทธิภาพของคำค้นหาในเครื่อง

SDK มีวิธีการลบดัชนีการค้นหา

ปิดใช้และเปิดใช้การเข้าถึงเครือข่าย

คุณใช้วิธีการด้านล่างเพื่อปิดการเข้าถึงเครือข่ายสำหรับไคลเอ็นต์ Cloud Firestore ได้ ขณะที่การเข้าถึงเครือข่ายปิดใช้อยู่ โปรแกรมฟังสแนปชอตและคำขอเอกสารทั้งหมดจะดึงผลลัพธ์จากแคช ระบบจะจัดคิวการดำเนินการเขียนไว้จนกว่าจะมีการเปิดใช้การเข้าถึงเครือข่ายอีกครั้ง

Web

import { disableNetwork } from "firebase/firestore"; 

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

Web

firebase.firestore().disableNetwork()
    .then(() => {
        // Do offline actions
        // ...
    });
Swift
หมายเหตุ: ผลิตภัณฑ์นี้ไม่พร้อมใช้งานบนเป้าหมาย watchOS และ App Clip
Firestore.firestore().disableNetwork { (error) in
  // Do offline things
  // ...
}
Objective-C
หมายเหตุ: ผลิตภัณฑ์นี้ไม่พร้อมใช้งานบนเป้าหมาย watchOS และ App Clip
[[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
});

ใช้วิธีการต่อไปนี้เพื่อเปิดใช้การเข้าถึงเครือข่ายอีกครั้ง

Web

import { enableNetwork } from "firebase/firestore"; 

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

Web

firebase.firestore().enableNetwork()
    .then(() => {
        // Do online actions
        // ...
    });
Swift
หมายเหตุ: ผลิตภัณฑ์นี้ไม่พร้อมใช้งานบนเป้าหมาย watchOS และ App Clip
Firestore.firestore().enableNetwork { (error) in
  // Do online things
  // ...
}
Objective-C
หมายเหตุ: ผลิตภัณฑ์นี้ไม่พร้อมใช้งานบนเป้าหมาย watchOS และ App Clip
[[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
});