获取我们在 Firebase 峰会上发布的所有信息,了解 Firebase 可如何帮助您加快应用开发速度并满怀信心地运行应用。了解详情

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

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

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

กำหนดค่าการคงอยู่แบบออฟไลน์

เมื่อคุณเริ่มต้น Cloud Firestore คุณสามารถเปิดหรือปิดใช้งานการคงอยู่แบบออฟไลน์:

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

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

// Any additional options
// ...

// Enable offline data persistence
let db = Firestore.firestore()
db.settings = settings
วัตถุประสงค์-C
หมายเหตุ: ผลิตภัณฑ์นี้ไม่พร้อมใช้งานบนเป้าหมาย watchOS และ App Clip
FIRFirestoreSettings *settings = [[FIRFirestoreSettings alloc] init];
settings.persistenceEnabled = YES;

// Any additional options
// ...

// Enable offline data persistence
FIRFirestore *db = [FIRFirestore firestore];
db.settings = settings;

Kotlin+KTX

val settings = firestoreSettings {
    isPersistenceEnabled = true
}
db.firestoreSettings = settings

Java

FirebaseFirestoreSettings settings = new FirebaseFirestoreSettings.Builder()
        .setPersistenceEnabled(true)
        .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 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
});
สวิฟต์
หมายเหตุ: ผลิตภัณฑ์นี้ไม่พร้อมใช้งานบนเป้าหมาย 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
settings.cacheSizeBytes = FirestoreCacheSizeUnlimited
Firestore.firestore().settings = settings
วัตถุประสงค์-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;
settings.cacheSizeBytes = kFIRFirestoreCacheSizeUnlimited;
[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 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);
      });
  });
สวิฟต์
หมายเหตุ: ผลิตภัณฑ์นี้ไม่พร้อมใช้งานบนเป้าหมาย 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)")
}
วัตถุประสงค์-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 ของแพลตฟอร์ม Apple มีเมธอด setIndexConfiguration ที่อ่านการกำหนดค่าที่มีโครงสร้าง JSON แบบเดียวกับที่ใช้กำหนดค่าดัชนีบนเซิร์ฟเวอร์ ตาม รูปแบบข้อกำหนดดัชนี เดียวกัน

// You will normally read this from a file asset or cloud storage.
let indexConfigJson = """
  {
    indexes: [
        ...
    ],
    fieldOverrides: [
        ...
    ]
  }
"""

// Apply the configuration.
Firestore.firestore().setIndexConfiguration(indexConfigJson)
วัตถุประสงค์-C

SDK แพลตฟอร์ม Apple มี setIndexConfiguration ที่อ่านการกำหนดค่าที่มีโครงสร้าง JSON เดียวกับที่ใช้กำหนดค่าดัชนีบนเซิร์ฟเวอร์ ตาม รูปแบบข้อกำหนดดัชนี เดียวกัน

// 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 SDK มีเมธอด setIndexConfiguration ที่อ่านการกำหนดค่าที่มีโครงสร้าง JSON เดียวกับที่ใช้กำหนดค่าดัชนีบนเซิร์ฟเวอร์ ตาม รูปแบบข้อกำหนดดัชนี เดียวกัน

// 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 SDK มีเมธอด setIndexConfiguration ที่อ่านการกำหนดค่าที่มีโครงสร้าง JSON เดียวกับที่ใช้กำหนดค่าดัชนีบนเซิร์ฟเวอร์ ตาม รูปแบบข้อกำหนดดัชนี เดียวกัน

// You will normally read this from a file asset or cloud storage.
val indexConfigJson = """
{
  indexes: [
      ...
  ],
  fieldOverrides: [
      ...
  ]
}
"""

// Apply the configuration.
FirebaseFirestore.getInstance().setIndexConfiguration(indexConfigJson)

Dart

Flutter SDK มีเมธอด setIndexConfigurationFromJSON ที่อ่านการกำหนดค่าที่มีโครงสร้าง JSON เดียวกันกับที่ใช้กำหนดค่าดัชนีบนเซิร์ฟเวอร์ ตาม รูปแบบการกำหนดดัชนี เดียวกัน

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

หรืออีกทางหนึ่ง คุณสามารถใช้เมธอด setIndexConfiguration เพื่อกำหนดค่าดัชนีด้วย API ที่อิงตามคลาส

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

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

ในการทำให้การกำหนดค่าดัชนีออฟไลน์พร้อมสำหรับการโหลดในแอปไคลเอ็นต์ของคุณ:

  • รวบรวมและเผยแพร่ด้วยแอปของคุณ
  • ดาวน์โหลดได้จาก CDN
  • ดึงข้อมูลจากระบบจัดเก็บข้อมูล เช่น Cloud Storage สำหรับ Firebase

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

คุณสามารถใช้วิธีการด้านล่างเพื่อปิดการเข้าถึงเครือข่ายสำหรับไคลเอ็นต์ 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
        // ...
    });
สวิฟต์
หมายเหตุ: ผลิตภัณฑ์นี้ไม่พร้อมใช้งานบนเป้าหมาย watchOS และ App Clip
Firestore.firestore().disableNetwork { (error) in
    // Do offline things
    // ...
}
วัตถุประสงค์-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 version 9

import { enableNetwork } from "firebase/firestore"; 

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

Web version 8

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