Mendapatkan Update Realtime dengan Cloud Firestore

Anda dapat mendeteksi dokumen dengan metode onSnapshot(). Panggilan awal menggunakan callback yang Anda berikan akan segera membuat snapshot dokumen dengan isi dokumen tunggal saat ini. Kemudian, setiap kali isinya berubah, panggilan lain akan mengupdate snapshot dokumen.

Web
db.collection("cities").doc("SF")
    .onSnapshot(function(doc) {
        console.log("Current data: ", doc.data());
    });
Swift
db.collection("cities").document("SF")
    .addSnapshotListener { documentSnapshot, error in
      guard let document = documentSnapshot else {
        print("Error fetching document: \(error!)")
        return
      }
      print("Current data: \(document.data())")
    }
Objective-C
[[[self.db collectionWithPath:@"cities"] documentWithPath:@"SF"]
    addSnapshotListener:^(FIRDocumentSnapshot *snapshot, NSError *error) {
      if (snapshot == nil) {
        NSLog(@"Error fetching document: %@", error);
        return;
      }
      NSLog(@"Current data: %@", snapshot.data);
    }];
  
Android
final DocumentReference docRef = db.collection("cities").document("SF");
docRef.addSnapshotListener(new EventListener<DocumentSnapshot>() {
    @Override
    public void onEvent(@Nullable DocumentSnapshot snapshot,
                        @Nullable FirebaseFirestoreException e) {
        if (e != null) {
            Log.w(TAG, "Listen failed.", e);
            return;
        }

        if (snapshot != null && snapshot.exists()) {
            Log.d(TAG, "Current data: " + snapshot.getData());
        } else {
            Log.d(TAG, "Current data: null");
        }
    }
});
Java
DocumentReference docRef = db.collection("cities").document("SF");
docRef.addSnapshotListener(new EventListener<DocumentSnapshot>() {
  @Override
  public void onEvent(@Nullable DocumentSnapshot snapshot,
                      @Nullable FirestoreException e) {
    if (e != null) {
      System.err.println("Listen failed: " + e);
      return;
    }

    if (snapshot != null && snapshot.exists()) {
      System.out.println("Current data: " + snapshot.getData());
    } else {
      System.out.print("Current data: null");
    }
  }
});
Python
# Not yet supported in Python client library
Node.js
var doc = db.collection('cities').doc('SF');

var observer = doc.onSnapshot(docSnapshot => {
  console.log(`Received doc snapshot: ${docSnapshot}`);
  // ...
}, err => {
  console.log(`Encountered error: ${err}`);
});
Go
// Not yet supported in Go client library
PHP
// Not yet supported in PHP client library

Peristiwa untuk perubahan lokal

Penulisan lokal dalam aplikasi Anda akan segera memanggil listener snapshot. Hal ini terjadi karena fitur penting yang disebut "kompensasi latensi". Saat Anda menjalankan operasi penulisan, listener akan menerima pemberitahuan mengenai data baru sebelum data tersebut dikirim ke backend.

Dokumen yang diambil memiliki properti metadata.hasPendingWrites yang menunjukkan apakah dokumen tersebut memiliki perubahan lokal yang belum ditulis ke backend atau tidak. Anda dapat menggunakan properti ini untuk menentukan sumber peristiwa yang diterima oleh listener snapshot:

Web
db.collection("cities").doc("SF")
    .onSnapshot(function(doc) {
        var source = doc.metadata.hasPendingWrites ? "Local" : "Server";
        console.log(source, " data: ", doc.data());
    });
Swift
db.collection("cities").document("SF")
    .addSnapshotListener { documentSnapshot, error in
        guard let document = documentSnapshot else {
            print("Error fetching document: \(error!)")
            return
        }
        let source = document.metadata.hasPendingWrites ? "Local" : "Server"
        print("\(source) data: \(document.data())")
    }
Objective-C
[[[self.db collectionWithPath:@"cities"] documentWithPath:@"SF"]
    addSnapshotListener:^(FIRDocumentSnapshot *snapshot, NSError *error) {
      if (snapshot == nil) {
        NSLog(@"Error fetching document: %@", error);
        return;
      }
      NSString *source = snapshot.metadata.hasPendingWrites ? @"Local" : @"Server";
      NSLog(@"%@ data: %@", source, snapshot.data);
    }];
  
Android
final DocumentReference docRef = db.collection("cities").document("SF");
docRef.addSnapshotListener(new EventListener<DocumentSnapshot>() {
    @Override
    public void onEvent(@Nullable DocumentSnapshot snapshot,
                        @Nullable FirebaseFirestoreException e) {
        if (e != null) {
            Log.w(TAG, "Listen failed.", e);
            return;
        }

        String source = snapshot != null && snapshot.getMetadata().hasPendingWrites()
                ? "Local" : "Server";

        if (snapshot != null && snapshot.exists()) {
            Log.d(TAG, source + " data: " + snapshot.getData());
        } else {
            Log.d(TAG, source + " data: null");
        }
    }
});
Java
# Not yet supported in the Java client library
Python
# Not yet supported in Python client library
Node.js
// Not yet supported in the Node.js client library
Go
// Not yet supported in Go client library
PHP
// Not yet supported in PHP client library

Peristiwa untuk perubahan metadata

Saat mendeteksi perubahan pada sebuah dokumen, koleksi, atau kueri, Anda dapat meneruskan opsi untuk mengontrol perincian peristiwa yang akan diterima listener.

Secara default, listener tidak akan diberi tahu mengenai perubahan yang hanya memengaruhi metadata. Pertimbangkan apa yang terjadi saat aplikasi Anda menulis sebuah dokumen baru:

  1. Peristiwa perubahan segera dipicu dengan data baru. Dokumen belum ditulis ke backend sehingga tanda "penulisan tertunda" bernilai true.
  2. Dokumen ditulis ke backend.
  3. Backend memberi tahu klien jika penulisan berhasil. Data dokumen tidak berubah, namun metadata berubah karena tanda "penulisan tertunda" sekarang bernilai false.

Jika Anda ingin menerima peristiwa snapshot saat metadata kueri atau dokumen berubah, teruskan objek opsi listen saat menambahkan listener:

Web
db.collection("cities").doc("SF")
    .onSnapshot({
        // Listen for document metadata changes
        includeMetadataChanges: true
    }, function(doc) {
        // ...
    });
Swift
// Listen to document metadata.
let options = DocumentListenOptions().includeMetadataChanges(true);

db.collection("cities").document("SF")
    .addSnapshotListener(options: options) { documentSnapshot, error in
        // ...
    }
Objective-C
// Listen for metadata changes.
FIRDocumentListenOptions *options = [[FIRDocumentListenOptions init] includeMetadataChanges:true]

[[[[self.db collectionWithPath:@"cities"] documentWithPath:@"SF"]
 addSnapshotListenerWithOptions:options listener:^(FIRDocumentSnapshot *snapshot, NSError *error) {
   // ...
 }]];
Android
// Listen for metadata changes to the document.
DocumentListenOptions options = new DocumentListenOptions()
        .includeMetadataChanges();

DocumentReference docRef = db.collection("cities").document("SF");
docRef.addSnapshotListener(options, new EventListener<DocumentSnapshot>() {
    @Override
    public void onEvent(@Nullable DocumentSnapshot snapshot,
                        @Nullable FirebaseFirestoreException e) {
        // ...
    }
});
Java
# Not yet supported in the Java client library
Python
# Not yet supported in Python client library
Node.js
// Not yet supported the Node.js client library
Go
// Not yet supported in Go client library
PHP
// Not yet supported in PHP client library

Mendeteksi beberapa dokumen dalam koleksi

Seperti pada dokumen, Anda dapat menggunakan onSnapshot(), dan bukan get() untuk mendeteksi hasil kueri. Dengan cara ini, snapshot kueri akan dibuat. Misalnya, untuk mendeteksi dokumen dengan negara bagian CA:

Web
db.collection("cities").where("state", "==", "CA")
    .onSnapshot(function(querySnapshot) {
        var cities = [];
        querySnapshot.forEach(function(doc) {
            cities.push(doc.data().name);
        });
        console.log("Current cities in CA: ", cities.join(", "));
    });
Swift
db.collection("cities").whereField("state", isEqualTo: "CA")
    .addSnapshotListener { querySnapshot, error in
        guard let documents = querySnapshot?.documents else {
            print("Error fetching documents: \(error!)")
            return
        }
        let cities = documents.map { $0["name"]! }
        print("Current cities in CA: \(cities)")
    }
Objective-C
[[[self.db collectionWithPath:@"cities"] queryWhereField:@"state" isEqualTo:@"CA"]
    addSnapshotListener:^(FIRQuerySnapshot *snapshot, NSError *error) {
      if (snapshot == nil) {
        NSLog(@"Error fetching documents: %@", error);
        return;
      }
      NSMutableArray *cities = [NSMutableArray array];
      for (FIRDocumentSnapshot *document in snapshot.documents) {
        [cities addObject:document.data[@"name"]];
      }
      NSLog(@"Current cities in CA: %@", cities);
    }];
  
Android
db.collection("cities")
        .whereEqualTo("state", "CA")
        .addSnapshotListener(new EventListener<QuerySnapshot>() {
            @Override
            public void onEvent(@Nullable QuerySnapshot value,
                                @Nullable FirebaseFirestoreException e) {
                if (e != null) {
                    Log.w(TAG, "Listen failed.", e);
                    return;
                }

                List<String> cities = new ArrayList<>();
                for (QueryDocumentSnapshot doc : value) {
                    if (doc.get("name") != null) {
                        cities.add(doc.getString("name"));
                    }
                }
                Log.d(TAG, "Current cites in CA: " + cities);
            }
        });
Java
db.collection("cities")
    .whereEqualTo("state", "CA")
    .addSnapshotListener(new EventListener<QuerySnapshot>() {
      @Override
      public void onEvent(@Nullable QuerySnapshot snapshots,
                          @Nullable FirestoreException e) {
        if (e != null) {
          System.err.println("Listen failed:" + e);
          return;
        }

        List<String> cities = new ArrayList<>();
        for (DocumentSnapshot doc : snapshots) {
          if (doc.get("name") != null) {
            cities.add(doc.getString("name"));
          }
        }
        System.out.println("Current cites in CA: " + cities);
      }
    });
Python
# Not yet supported in Python client library
Node.js
var query = db.collection('cities').where('state', '==', 'CA');

var observer = query.onSnapshot(querySnapshot => {
  console.log(`Received query snapshot of size ${querySnapshot.size}`);
  // ...
}, err => {
  console.log(`Encountered error: ${err}`);
});
Go
// Not yet supported in Go client library
PHP
// Not yet supported in PHP client library

Penangan snapshot akan menerima snapshot kueri baru setiap kali hasil kueri berubah (yakni, jika dokumen ditambahkan, dihapus, atau dimodifikasi).

Melihat perubahan di antara snapshot

Melihat perubahan aktual pada hasil kueri di antara berbagai snapshot kueri sering kali berguna dibandingkan menggunakan keseluruhan snapshot kueri. Misalnya, Anda dapat mengelola cache saat dokumen individual ditambahkan, dihapus, dan diubah.

Web
db.collection("cities").where("state", "==", "CA")
    .onSnapshot(function(snapshot) {
        snapshot.docChanges.forEach(function(change) {
            if (change.type === "added") {
                console.log("New city: ", change.doc.data());
            }
            if (change.type === "modified") {
                console.log("Modified city: ", change.doc.data());
            }
            if (change.type === "removed") {
                console.log("Removed city: ", change.doc.data());
            }
        });
    });
Swift
db.collection("cities").whereField("state", isEqualTo: "CA")
    .addSnapshotListener { querySnapshot, error in
        guard let snapshot = querySnapshot else {
            print("Error fetching snapshots: \(error!)")
            return
        }
        snapshot.documentChanges.forEach { diff in
            if (diff.type == .added) {
                print("New city: \(diff.document.data())")
            }
            if (diff.type == .modified) {
                print("Modified city: \(diff.document.data())")
            }
            if (diff.type == .removed) {
                print("Removed city: \(diff.document.data())")
            }
        }
    }
Objective-C
[[[self.db collectionWithPath:@"cities"] queryWhereField:@"state" isEqualTo:@"CA"]
    addSnapshotListener:^(FIRQuerySnapshot *snapshot, NSError *error) {
      if (snapshot == nil) {
        NSLog(@"Error fetching documents: %@", error);
        return;
      }
      for (FIRDocumentChange *diff in snapshot.documentChanges) {
        if (diff.type == FIRDocumentChangeTypeAdded) {
          NSLog(@"New city: %@", diff.document.data);
        }
        if (diff.type == FIRDocumentChangeTypeModified) {
          NSLog(@"Modified city: %@", diff.document.data);
        }
        if (diff.type == FIRDocumentChangeTypeRemoved) {
          NSLog(@"Removed city: %@", diff.document.data);
        }
      }
    }];
  
Android
db.collection("cities")
        .whereEqualTo("state", "CA")
        .addSnapshotListener(new EventListener<QuerySnapshot>() {
            @Override
            public void onEvent(@Nullable QuerySnapshot snapshots,
                                @Nullable FirebaseFirestoreException e) {
                if (e != null) {
                    Log.w(TAG, "listen:error", e);
                    return;
                }

                for (DocumentChange dc : snapshots.getDocumentChanges()) {
                    switch (dc.getType()) {
                        case ADDED:
                            Log.d(TAG, "New city: " + dc.getDocument().getData());
                            break;
                        case MODIFIED:
                            Log.d(TAG, "Modified city: " + dc.getDocument().getData());
                            break;
                        case REMOVED:
                            Log.d(TAG, "Removed city: " + dc.getDocument().getData());
                            break;
                    }
                }

            }
        });
Java
db.collection("cities")
    .whereEqualTo("state", "CA")
    .addSnapshotListener(new EventListener<QuerySnapshot>() {
      @Override
      public void onEvent(@Nullable QuerySnapshot snapshots,
                          @Nullable FirestoreException e) {
        if (e != null) {
          System.err.println("Listen failed: " + e);
          return;
        }

        for (DocumentChange dc : snapshots.getDocumentChanges()) {
          switch (dc.getType()) {
            case ADDED:
              System.out.println("New city: " + dc.getDocument().getData());
              break;
            case MODIFIED:
              System.out.println("Modified city: " + dc.getDocument().getData());
              break;
            case REMOVED:
              System.out.println("Removed city: " + dc.getDocument().getData());
              break;
            default:
              break;
          }
        }
      }
    });
Python
# Not yet supported in the Python client library
Node.js
// Not yet supported in the Node.js client library
Go
// Not yet supported in Go client library
PHP
// Not yet supported in PHP client library

Status awal dapat berasal dari server secara langsung atau dari cache lokal. Jika ada status yang tersedia di cache lokal, snapshot kueri pada awalnya akan terisi dengan data yang tersimpan dalam cache, kemudian diupdate dengan data server saat klien mengetahui status server.

Melepaskan listener

Jika tidak tertarik lagi untuk mendeteksi data, Anda harus melepaskan listener agar callback peristiwa berhenti dipanggil. Dengan demikian, klien dapat berhenti menggunakan bandwidth untuk menerima update. Anda dapat menggunakan fungsi unsubscribe pada onSnapshot() untuk berhenti mendeteksi update.

Web
var unsubscribe = db.collection("cities")
    .onSnapshot(function () {});
// ...
// Stop listening to changes
unsubscribe();
Swift
let listener = db.collection("cities").addSnapshotListener { querySnapshot, error in
    // ...
}

// ...

// Stop listening to changes
listener.remove()
Objective-C
id<FIRListenerRegistration> listener = [[self.db collectionWithPath:@"cities"]
    addSnapshotListener:^(FIRQuerySnapshot *snapshot, NSError *error) {
      // ...
}];

// ...

// Stop listening to changes
[listener remove];
  
Android
Query query = db.collection("cities");
ListenerRegistration registration = query.addSnapshotListener(
        new EventListener<QuerySnapshot>() {
            // ...
        });

// ...

// Stop listening to changes
registration.remove();
Java
Query query = db.collection("cities");
ListenerRegistration registration = query.addSnapshotListener(
    new EventListener<QuerySnapshot>() {
      // ...
    });

// ...

// Stop listening to changes
registration.remove();
Python
# Not yet supported in the Python client library
Node.js
var unsub = db.collection('cities').onSnapshot(() => {});

// ...

// Stop listening for changes
unsub();
Go
// Not yet supported in Go client library
PHP
// Not yet supported in PHP client library

Menangani error deteksi

Proses mendeteksi terkadang dapat mengalami kegagalan, misalnya, karena izin keamanan atau jika Anda mencoba mendeteksi kueri yang tidak valid. (Pelajari lebih lanjut tentang kueri yang valid dan tidak valid.) Untuk menangani kegagalan ini, Anda dapat memberikan callback error saat memasang listener snapshot. Setelah error muncul, listener tidak akan menerima peristiwa lagi, sehingga Anda tidak perlu melepaskan listener.

Web
db.collection("cities")
    .onSnapshot(function(snapshot) {
        //...
    }, function(error) {
        //...
    });
Swift
db.collection("cities")
    .addSnapshotListener { querySnapshot, error in
        if let error = error {
            print("Error retreiving collection: \(error)")
        }
    }
Objective-C
[[self.db collectionWithPath:@"cities"]
    addSnapshotListener:^(FIRQuerySnapshot *snapshot, NSError *error) {
      if (error != nil) {
        NSLog(@"Error retreving collection: %@", error);
      }
    }];
  
Android
db.collection("cities")
        .addSnapshotListener(new EventListener<QuerySnapshot>() {
            @Override
            public void onEvent(@Nullable QuerySnapshot snapshots,
                                @Nullable FirebaseFirestoreException e) {
                if (e != null) {
                    Log.w(TAG, "listen:error", e);
                    return;
                }

                for (DocumentChange dc : snapshots.getDocumentChanges()) {
                    if (dc.getType() == Type.ADDED) {
                        Log.d(TAG, "New city: " + dc.getDocument().getData());
                    }
                }

            }
        });
Java
db.collection("cities")
    .addSnapshotListener(new EventListener<QuerySnapshot>() {
      @Override
      public void onEvent(@Nullable QuerySnapshot snapshots,
                          @Nullable FirestoreException e) {
        if (e != null) {
          System.err.println("Listen failed: " + e);
          return;
        }

        for (DocumentChange dc : snapshots.getDocumentChanges()) {
          if (dc.getType() == Type.ADDED) {
            System.out.println("New city: " + dc.getDocument().getData());
          }
        }
      }
    });
Python
# Not yet supported in the Python client library
Node.js
db.collection('cities')
    .onSnapshot((snapshot) => {
      //...
    }, (error) => {
      //...
    });
Go
// Not yet supported in Go client library
PHP
// Not yet supported in PHP client library

Kirim masukan tentang...

Butuh bantuan? Kunjungi halaman dukungan kami.