Catch up on everything announced at Firebase Summit, and learn how Firebase can help you accelerate app development and run your app with confidence. Learn More

Truy cập dữ liệu ngoại tuyến

Sử dụng bộ sưu tập để sắp xếp ngăn nắp các trang Lưu và phân loại nội dung dựa trên lựa chọn ưu tiên của bạn.

Cloud Firestore hỗ trợ lưu trữ dữ liệu ngoại tuyến. Tính năng này lưu vào bộ nhớ cache một bản sao của dữ liệu Cloud Firestore mà ứng dụng của bạn đang sử dụng, vì vậy ứng dụng của bạn có thể truy cập dữ liệu khi thiết bị ngoại tuyến. Bạn có thể viết, đọc, nghe và truy vấn dữ liệu đã lưu trong bộ nhớ cache. Khi thiết bị trực tuyến trở lại, Cloud Firestore sẽ đồng bộ hóa mọi thay đổi cục bộ do ứng dụng của bạn thực hiện với phần phụ trợ Cloud Firestore.

Để sử dụng tính năng duy trì ngoại tuyến, bạn không cần thực hiện bất kỳ thay đổi nào đối với mã mà bạn sử dụng để truy cập dữ liệu Cloud Firestore. Với tính năng duy trì ngoại tuyến được bật, thư viện máy khách Cloud Firestore tự động quản lý truy cập dữ liệu trực tuyến và ngoại tuyến và đồng bộ hóa dữ liệu cục bộ khi thiết bị trực tuyến trở lại.

Định cấu hình độ bền ngoại tuyến

Khi bạn khởi chạy Cloud Firestore, bạn có thể bật hoặc tắt tính năng duy trì ngoại tuyến:

  • Đối với các nền tảng Android và Apple, tính năng ổn định ngoại tuyến được bật theo mặc định. Để tắt tính năng duy trì, hãy đặt tùy chọn PersistenceEnabled thành false .
  • Đối với web, tính năng duy trì ngoại tuyến bị tắt theo mặc định. Để kích hoạt tính bền bỉ, hãy gọi phương thức enablePersistence . Bộ nhớ cache của Cloud Firestore không tự động bị xóa giữa các phiên. Do đó, nếu ứng dụng web của bạn xử lý thông tin nhạy cảm, hãy nhớ hỏi người dùng xem họ có đang sử dụng thiết bị đáng tin cậy hay không trước khi bật tính năng duy trì.

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
Nhanh
Lưu ý: Sản phẩm này không khả dụng trên các mục tiêu watchOS và App Clip.
let settings = FirestoreSettings()
settings.isPersistenceEnabled = true

// Any additional options
// ...

// Enable offline data persistence
let db = Firestore.firestore()
db.settings = settings
Objective-C
Lưu ý: Sản phẩm này không khả dụng trên các mục tiêu watchOS và App Clip.
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));

Định cấu hình kích thước bộ nhớ cache

Khi tính năng duy trì được bật, Cloud Firestore lưu trữ mọi tài liệu nhận được từ chương trình phụ trợ để truy cập ngoại tuyến. Cloud Firestore đặt ngưỡng mặc định cho kích thước bộ nhớ cache. Sau khi vượt quá mặc định, Cloud Firestore định kỳ cố gắng dọn dẹp các tài liệu cũ hơn, không sử dụng. Bạn có thể định cấu hình ngưỡng kích thước bộ nhớ cache khác hoặc tắt hoàn toàn quá trình dọn dẹp:

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
});
Nhanh
Lưu ý: Sản phẩm này không khả dụng trên các mục tiêu watchOS và 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
Objective-C
Lưu ý: Sản phẩm này không khả dụng trên các mục tiêu watchOS và 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;
  

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

Nghe dữ liệu ngoại tuyến

Trong khi thiết bị ngoại tuyến, nếu bạn đã bật tính năng duy trì ngoại tuyến, người nghe của bạn sẽ nhận được các sự kiện nghe khi dữ liệu được lưu trong bộ nhớ cache cục bộ thay đổi. Bạn có thể nghe tài liệu, bộ sưu tập và truy vấn.

Để kiểm tra xem bạn đang nhận dữ liệu từ máy chủ hay bộ đệm, hãy sử dụng thuộc tính fromCache trên SnapshotMetadata trong sự kiện ảnh chụp nhanh của bạn. Nếu fromCachetrue , dữ liệu đến từ cache và có thể cũ hoặc không đầy đủ. Nếu fromCachefalse , dữ liệu đã hoàn chỉnh và cập nhật mới nhất trên máy chủ.

Theo mặc định, không có sự kiện nào được đưa ra nếu chỉ thay đổi SnapshotMetadata . Nếu bạn dựa vào các giá trị fromCache , hãy chỉ định tùy chọn nghe includeMetadataChanges khi bạn đính kèm trình xử lý lắng nghe của mình.

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);
      });
  });
Nhanh
Lưu ý: Sản phẩm này không khả dụng trên các mục tiêu watchOS và 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
Lưu ý: Sản phẩm này không khả dụng trên các mục tiêu watchOS và 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);
    }];

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

Nhận dữ liệu ngoại tuyến

Nếu bạn nhận được tài liệu trong khi thiết bị ngoại tuyến, Cloud Firestore sẽ trả lại dữ liệu từ bộ nhớ cache.

Khi truy vấn một bộ sưu tập, một kết quả trống được trả về nếu không có tài liệu được lưu trong bộ nhớ cache. Thay vào đó, khi tìm nạp một tài liệu cụ thể, một lỗi sẽ được trả về.

Truy vấn dữ liệu ngoại tuyến

Truy vấn hoạt động với tính ổn định ngoại tuyến. Bạn có thể truy xuất kết quả của các truy vấn bằng cách lấy trực tiếp hoặc bằng cách lắng nghe, như được mô tả trong các phần trước. Bạn cũng có thể tạo truy vấn mới trên dữ liệu lưu trữ cục bộ trong khi thiết bị ngoại tuyến, nhưng ban đầu các truy vấn sẽ chỉ chạy trên các tài liệu được lưu trong bộ nhớ cache.

Định cấu hình chỉ mục truy vấn ngoại tuyến

Theo mặc định, Firestore SDK quét tất cả các tài liệu trong một bộ sưu tập trong bộ nhớ cache cục bộ của nó khi thực hiện các truy vấn ngoại tuyến. Với hành vi mặc định này, hiệu suất truy vấn ngoại tuyến có thể bị ảnh hưởng khi người dùng ngoại tuyến trong thời gian dài.

Nền tảng Apple , Android và SDK JavaScript cung cấp phương pháp setIndexConfiguration cho phép bạn định cấu hình các chỉ mục truy vấn cục bộ để cải thiện hiệu suất của các truy vấn ngoại tuyến của bạn.

Các phương thức này đọc cùng một cấu hình có cấu trúc JSON được sử dụng để định cấu hình các chỉ mục trên máy chủ, tuân theo cùng một định dạng định nghĩa chỉ mục .

Cấu hình chỉ mục ngoại tuyến để sử dụng phụ thuộc vào bộ sưu tập và tài liệu mà ứng dụng của bạn truy cập nhiều khi ngoại tuyến và hiệu suất ngoại tuyến mà bạn muốn. Mặc dù bạn có thể xuất cấu hình chỉ mục phụ trợ của mình để sử dụng trên ứng dụng khách, nhưng các mẫu truy cập ngoại tuyến của ứng dụng có thể khác đáng kể với các mẫu truy cập trực tuyến, do đó, cấu hình chỉ mục trực tuyến của bạn có thể không phù hợp để sử dụng ngoại tuyến. Những bộ sưu tập và tài liệu nào bạn muốn ứng dụng của mình truy cập ngoại tuyến với hiệu suất cao? Khi bạn đã phân tích hành vi của ứng dụng, hãy làm theo các nguyên tắc để xác định chỉ mục từ hướng dẫn lập chỉ mục .

Để cung cấp cấu hình chỉ mục ngoại tuyến để tải trong ứng dụng khách của bạn:

  • biên dịch và phân phối chúng với ứng dụng của bạn
  • tải chúng xuống từ CDN
  • tìm nạp chúng từ hệ thống lưu trữ như Cloud Storage cho Firebase .

Tắt và bật quyền truy cập mạng

Bạn có thể sử dụng phương pháp bên dưới để vô hiệu hóa quyền truy cập mạng cho ứng dụng Cloud Firestore của mình. Trong khi quyền truy cập mạng bị vô hiệu hóa, tất cả các trình nghe ảnh chụp nhanh và các yêu cầu tài liệu sẽ truy xuất kết quả từ bộ đệm. Các thao tác ghi được xếp hàng đợi cho đến khi quyền truy cập mạng được kích hoạt lại.

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
        // ...
    });
Nhanh
Lưu ý: Sản phẩm này không khả dụng trên các mục tiêu watchOS và App Clip.
Firestore.firestore().disableNetwork { (error) in
    // Do offline things
    // ...
}
Objective-C
Lưu ý: Sản phẩm này không khả dụng trên các mục tiêu watchOS và App Clip.
[[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
});

Sử dụng phương pháp sau để kích hoạt lại quyền truy cập mạng:

Web version 9

import { enableNetwork } from "firebase/firestore"; 

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

Web version 8

firebase.firestore().enableNetwork()
    .then(() => {
        // Do online actions
        // ...
    });
Nhanh
Lưu ý: Sản phẩm này không khả dụng trên các mục tiêu watchOS và App Clip.
Firestore.firestore().enableNetwork { (error) in
    // Do online things
    // ...
}
Objective-C
Lưu ý: Sản phẩm này không khả dụng trên các mục tiêu watchOS và App Clip.
[[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
});