Send feedback
Stay organized with collections
Save and categorize content based on your preferences.
Get real-time updates
You can listen
to a document with the onSnapshot()
method. An initial
call using the callback you provide creates a document snapshot immediately with
the current contents of the single document. Then, each time
the contents change, another call updates the document snapshot.
Note: Realtime listeners are not supported in the PHP client library.
Web version 9
Learn
more
about the tree-shakeable modular Web API and upgrade
from
the namespaced API.
import { doc, onSnapshot } from "firebase/firestore";
const unsub = onSnapshot(doc(db, "cities", "SF"), (doc) => {
console.log("Current data: ", doc.data());
});
Web version 8
Learn
more
about the tree-shakeable modular Web API and upgrade
from
the namespaced API.
db.collection("cities").doc("SF")
.onSnapshot((doc) => {
console.log("Current data: ", doc.data());
});
Swift
Note:
This product is not available on watchOS and App Clip targets.
db.collection("cities").document("SF")
.addSnapshotListener { documentSnapshot, error in
guard let document = documentSnapshot else {
print("Error fetching document: \(error!)")
return
}
guard let data = document.data() else {
print("Document data was empty.")
return
}
print("Current data: \(data)")
}
Objective-C
Note:
This product is not available on watchOS and App Clip targets.
[[[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);
}];
Kotlin+KTX Android
val docRef = db.collection("cities").document("SF")
docRef.addSnapshotListener { snapshot, e ->
if (e != null) {
Log.w(TAG, "Listen failed.", e)
return@addSnapshotListener
}
if (snapshot != null && snapshot.exists()) {
Log.d(TAG, "Current data: ${snapshot.data}")
} else {
Log.d(TAG, "Current data: null")
}
}
Java 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");
}
}
});
Dart
final docRef = db.collection("cities").doc("SF");
docRef.snapshots().listen(
(event) => print("current data: ${event.data()}"),
onError: (error) => print("Listen failed: $error"),
);
Often, you want your UI to react to changes in the contents of a Firestore
document or collection. You can do so with a StreamBuilder
widget that consumes the Firestore snapshot stream:
class UserInformation extends StatefulWidget {
@override
_UserInformationState createState() => _UserInformationState();
}
class _UserInformationState extends State<UserInformation> {
final Stream<QuerySnapshot> _usersStream =
FirebaseFirestore.instance.collection('users').snapshots();
@override
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: _usersStream,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return const Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return const Text("Loading");
}
return ListView(
children: snapshot.data!.docs
.map((DocumentSnapshot document) {
Map<String, dynamic> data =
document.data()! as Map<String, dynamic>;
return ListTile(
title: Text(data['full_name']),
subtitle: Text(data['company']),
);
})
.toList()
.cast(),
);
},
);
}
}
C++
DocumentReference doc_ref = db->Collection("cities").Document("SF");
doc_ref.AddSnapshotListener(
[](const DocumentSnapshot& snapshot, Error error, const std::string& errorMsg) {
if (error == Error::kErrorOk) {
if (snapshot.exists()) {
std::cout << "Current data: " << snapshot << std::endl;
} else {
std::cout << "Current data: null" << std::endl;
}
} else {
std::cout << "Listen failed: " << error << std::endl;
}
});
PHP
// Not supported in the PHP client library
Unity
DocumentReference docRef = db.Collection("cities").Document("SF");
docRef.Listen(snapshot => {
Debug.Log("Callback received document snapshot.");
Debug.Log(String.Format("Document data for {0} document:", snapshot.Id));
Dictionary<string, object> city = snapshot.ToDictionary();
foreach (KeyValuePair<string, object> pair in city) {
Debug.Log(String.Format("{0}: {1}", pair.Key, pair.Value));
}
});
Events for local changes
Local writes in your app will invoke snapshot listeners immediately.
This is because of an important feature called "latency compensation."
When you perform a write, your listeners will be notified with the new
data before
the data is sent to the backend.
Retrieved documents have a metadata.hasPendingWrites
property that indicates
whether the document has local changes that haven't been written to the backend
yet. You can use this property to determine the source of events received by
your snapshot listener:
Web version 9
Learn
more
about the tree-shakeable modular Web API and upgrade
from
the namespaced API.
import { doc, onSnapshot } from "firebase/firestore";
const unsub = onSnapshot(doc(db, "cities", "SF"), (doc) => {
const source = doc.metadata.hasPendingWrites ? "Local" : "Server";
console.log(source, " data: ", doc.data());
});
Web version 8
Learn
more
about the tree-shakeable modular Web API and upgrade
from
the namespaced API.
db.collection("cities").doc("SF")
.onSnapshot((doc) => {
var source = doc.metadata.hasPendingWrites ? "Local" : "Server";
console.log(source, " data: ", doc.data());
});
Swift
Note:
This product is not available on watchOS and App Clip targets.
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
Note:
This product is not available on watchOS and App Clip targets.
[[[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);
}];
Kotlin+KTX Android
val docRef = db.collection("cities").document("SF")
docRef.addSnapshotListener { snapshot, e ->
if (e != null) {
Log.w(TAG, "Listen failed.", e)
return@addSnapshotListener
}
val source = if (snapshot != null && snapshot.metadata.hasPendingWrites()) {
"Local"
} else {
"Server"
}
if (snapshot != null && snapshot.exists()) {
Log.d(TAG, "$source data: ${snapshot.data}")
} else {
Log.d(TAG, "$source data: null")
}
}
Java 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");
}
}
});
Dart
final docRef = db.collection("cities").doc("SF");
docRef.snapshots().listen(
(event) {
final source = (event.metadata.hasPendingWrites) ? "Local" : "Server";
print("$source data: ${event.data()}");
},
onError: (error) => print("Listen failed: $error"),
);
Java
# Not yet supported in the Java client library
Python
// Not yet supported in Python client library
C++
DocumentReference doc_ref = db->Collection("cities").Document("SF");
doc_ref.AddSnapshotListener([](const DocumentSnapshot& snapshot,
Error error, const std::string& errorMsg) {
if (error == Error::kErrorOk) {
const char* source =
snapshot.metadata().has_pending_writes() ? "Local" : "Server";
if (snapshot.exists()) {
std::cout << source << " data: " << snapshot.Get("name").string_value()
<< std::endl;
} else {
std::cout << source << " data: null" << std::endl;
}
} else {
std::cout << "Listen failed: " << error << std::endl;
}
});
Node.js
// Not yet supported in the Node.js client library
Go
// Not yet supported in the Go client library
PHP
// Not supported in the PHP client library
Unity
DocumentReference docRef = db.Collection("cities").Document("SF");
docRef.Listen(
snapshot =>
{
string source = (snapshot != null && snapshot.Metadata.HasPendingWrites) ? "Local" : "Server";
string snapshotData = "null";
if (snapshot != null && snapshot.Exists)
{
System.Text.StringBuilder builder = new System.Text.StringBuilder();
IDictionary<string, object> dict = snapshot.ToDictionary();
foreach (var KVPair in dict)
{
builder.Append($"{KVPair.Key}: {KVPair.Value}\n");
}
snapshotData = builder.ToString();
}
Debug.Log($"{source} data: ${snapshotData}");
});
C#
// Not yet supported in the C# client library
Ruby
// Not yet supported in the Ruby client library
When listening for changes to a document, collection, or query, you can pass
options to control the granularity of events that your listener will receive.
By default, listeners are not notified of changes that only affect metadata.
Consider what happens when your app writes a new document:
A change event is immediately fired with the new data. The document
has not yet been written to the backend so the "pending writes"
flag is true
.
The document is written to the backend.
The backend notifies the client of the successful write. There is no
change to the document data, but there is a metadata change because
the "pending writes" flag is now false
.
If you want to receive snapshot events when the document or query metadata
changes, pass a listen options object when attaching your listener.
Web version 9
Learn
more
about the tree-shakeable modular Web API and upgrade
from
the namespaced API.
import { doc, onSnapshot } from "firebase/firestore";
const unsub = onSnapshot(
doc(db, "cities", "SF"),
{ includeMetadataChanges: true },
(doc) => {
// ...
});
Web version 8
Learn
more
about the tree-shakeable modular Web API and upgrade
from
the namespaced API.
db.collection("cities").doc("SF")
.onSnapshot({
// Listen for document metadata changes
includeMetadataChanges: true
}, (doc) => {
// ...
});
Swift
Note:
This product is not available on watchOS and App Clip targets.
// Listen to document metadata.
db.collection("cities").document("SF")
.addSnapshotListener(includeMetadataChanges: true) { documentSnapshot, error in
// ...
}
Objective-C
Note:
This product is not available on watchOS and App Clip targets.
// Listen for metadata changes.
[[[self.db collectionWithPath:@"cities"] documentWithPath:@"SF"]
addSnapshotListenerWithIncludeMetadataChanges:YES
listener:^(FIRDocumentSnapshot *snapshot, NSError *error) {
// ...
}];
Kotlin+KTX Android
// Listen for metadata changes to the document.
val docRef = db.collection("cities").document("SF")
docRef.addSnapshotListener(MetadataChanges.INCLUDE) { snapshot, e ->
// ...
}
Java Android
// Listen for metadata changes to the document.
DocumentReference docRef = db.collection("cities").document("SF");
docRef.addSnapshotListener(MetadataChanges.INCLUDE, new EventListener<DocumentSnapshot>() {
@Override
public void onEvent(@Nullable DocumentSnapshot snapshot,
@Nullable FirebaseFirestoreException e) {
// ...
}
});
Dart
final docRef = db.collection("cities").doc("SF");
docRef.snapshots(includeMetadataChanges: true).listen((event) {
// ...
});
Java
// Not yet supported in the Java client library
Python
// Not yet supported in Python client library
C++
DocumentReference doc_ref = db->Collection("cities").Document("SF");
doc_ref.AddSnapshotListener(
MetadataChanges::kInclude,
[](const DocumentSnapshot& snapshot, Error error, const std::string& errorMsg) { /* ... */ });
Node.js
// Not yet supported the Node.js client library
Go
// Not yet supported in the Go client library
PHP
// Not supported in the PHP client library
Unity
DocumentReference docRef = db.Collection("cities").Document("SF");
docRef.Listen(MetadataChanges.Include, snapshot =>
{
// ...
});
C#
// Not yet supported in the C# client library
Ruby
// Not yet supported in the Ruby client library
Note: If you just want to know when your write has completed, you can listen to
the completion callback rather than using hasPendingWrites
. In JavaScript, use
the Promise
returned from your write operation by attaching a .then()
callback. In Swift, pass a completion callback to your write function.
Configure listeners for local changes only
Firestore snapshot listeners take an initial snapshot from the local cache
and concurrently fetch corresponding data from the server.
In some cases, you may not want follow-up fetches from the server. Client SDKs
allow you to configure listeners to fire only with respect to data in the local
cache. This helps you avoid unnecessary server calls and their costs, and
leverage the client-side cache, which reflects local data and mutations.
Here, snapshot options are set in client code to allow listening for local
changes only.
Web version 9
Learn
more
about the tree-shakeable modular Web API and upgrade
from
the namespaced API.
const unsubscribe = onSnapshot(
doc(db, "cities", "SF"),
{
includeMetadataChanges: true,
source:'cache'
},
(documentSnapshot) => {//…}
);
Web version 8
Learn
more
about the tree-shakeable modular Web API and upgrade
from
the namespaced API.
// Not yet supported in the Web namespaced API
Swift
Note:
This product is not available on watchOS and App Clip targets.
// Set up listener options
let options = SnapshotListenOptions()
.withSource(ListenSource.cache)
.withIncludeMetadataChanges(true)
db.collection("cities").document("SF")
.addSnapshotListener(options: options) { documentSnapshot, error in
// ...
}
Objective-C
Note:
This product is not available on watchOS and App Clip targets.
// Set up listener options
FIRSnapshotListenOptions *options = [[FIRSnapshotListenOptions alloc] init];
FIRSnapshotListenOptions *optionsWithSourceAndMetadata =
[[options optionsWithIncludeMetadataChanges:YES]
optionsWithSource:FIRListenSourceCache];
[[[self.db collectionWithPath:@"cities"] documentWithPath:@"SF"]
addSnapshotListenerWithOptions:optionsWithSourceAndMetadata
listener: ^ (FIRDocumentSnapshot * snapshot, NSError * error) {
//…
}
];
Kotlin+KTX Android
// Set up listener options
val options = SnapshotListenOptions.Builder()
.setMetadataChanges(MetadataChanges.INCLUDE)
.setSource(ListenSource.CACHE)
.build();
db.collection("cities").document("SF")
.addSnapshotListener(options) { snapshot, error ->
//…
}
Java Android
// Set up listener options
SnapshotListenOptions options = new SnapshotListenOptions.Builder()
.setMetadataChanges(MetadataChanges.INCLUDE)
.setSource(ListenSource.CACHE)
.build();
db.collection("cities").document("SF").addSnapshotListener(options, new EventListener<DocumentSnapshot>() {
//…
});
Dart
// Not yet supported in this client library
Java
# Not yet supported in the Java client library
Python
// Not yet supported in Python client library
C++
// Not yet supported in the C++ client library
Node.js
// Not yet supported in the Node.js client library
Go
// Not yet supported in the Go client library
PHP
// Not yet supported in the PHP client library
Unity
// Not yet supported in the Unity client library
C#
// Not yet supported in the C# client library
Ruby
// Not yet supported in the Ruby client library
Listen to multiple documents in a collection
As with documents, you can use onSnapshot()
instead of get()
to listen to the
results of a query. This creates a query snapshot. For example, to listen to the
documents with state CA
:
Web version 9
Learn
more
about the tree-shakeable modular Web API and upgrade
from
the namespaced API.
import { collection, query, where, onSnapshot } from "firebase/firestore";
const q = query(collection(db, "cities"), where("state", "==", "CA"));
const unsubscribe = onSnapshot(q, (querySnapshot) => {
const cities = [];
querySnapshot.forEach((doc) => {
cities.push(doc.data().name);
});
console.log("Current cities in CA: ", cities.join(", "));
});
Web version 8
Learn
more
about the tree-shakeable modular Web API and upgrade
from
the namespaced API.
db.collection("cities").where("state", "==", "CA")
.onSnapshot((querySnapshot) => {
var cities = [];
querySnapshot.forEach((doc) => {
cities.push(doc.data().name);
});
console.log("Current cities in CA: ", cities.join(", "));
});
Swift
Note:
This product is not available on watchOS and App Clip targets.
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.compactMap { $0["name"] }
print("Current cities in CA: \(cities)")
}
Objective-C
Note:
This product is not available on watchOS and App Clip targets.
[[[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);
}];
Kotlin+KTX Android
db.collection("cities")
.whereEqualTo("state", "CA")
.addSnapshotListener { value, e ->
if (e != null) {
Log.w(TAG, "Listen failed.", e)
return@addSnapshotListener
}
val cities = ArrayList<String>()
for (doc in value!!) {
doc.getString("name")?.let {
cities.add(it)
}
}
Log.d(TAG, "Current cites in CA: $cities")
}
Java 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);
}
});
Dart
db
.collection("cities")
.where("state", isEqualTo: "CA")
.snapshots()
.listen((event) {
final cities = [];
for (var doc in event.docs) {
cities.add(doc.data()["name"]);
}
print("cities in CA: ${cities.join(", ")}");
});
C++
db->Collection("cities")
.WhereEqualTo("state", FieldValue::String("CA"))
.AddSnapshotListener([](const QuerySnapshot& snapshot, Error error, const std::string& errorMsg) {
if (error == Error::kErrorOk) {
std::vector<std::string> cities;
std::cout << "Current cities in CA: " << error << std::endl;
for (const DocumentSnapshot& doc : snapshot.documents()) {
cities.push_back(doc.Get("name").string_value());
std::cout << "" << cities.back() << std::endl;
}
} else {
std::cout << "Listen failed: " << error << std::endl;
}
});
PHP
// Not supported in the PHP client library
Unity
Query query = db.Collection("cities").WhereEqualTo("State", "CA");
ListenerRegistration listener = query.Listen(snapshot => {
Debug.Log("Callback received query snapshot.");
Debug.Log("Current cities in California:");
foreach (DocumentSnapshot documentSnapshot in snapshot.Documents) {
Debug.Log(documentSnapshot.Id);
}
});
The snapshot handler will receive a new query snapshot every time the query
results change (that is, when a document is added, removed, or modified).
Important: As explained above under Events for local
changes
, you will receive events immediately
for your
local writes. Your listener can use the metadata.hasPendingWrites
field on
each document to determine whether the document has local changes that have not
yet been written to the backend.
View changes between snapshots
It is often useful to see the actual changes to query results between query
snapshots, instead of simply using the entire query snapshot. For example, you
may want to maintain a cache as individual documents are added, removed, and
modified.
Web version 9
Learn
more
about the tree-shakeable modular Web API and upgrade
from
the namespaced API.
import { collection, query, where, onSnapshot } from "firebase/firestore";
const q = query(collection(db, "cities"), where("state", "==", "CA"));
const unsubscribe = onSnapshot(q, (snapshot) => {
snapshot.docChanges().forEach((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());
}
});
});
Web version 8
Learn
more
about the tree-shakeable modular Web API and upgrade
from
the namespaced API.
db.collection("cities").where("state", "==", "CA")
.onSnapshot((snapshot) => {
snapshot.docChanges().forEach((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
Note:
This product is not available on watchOS and App Clip targets.
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
Note:
This product is not available on watchOS and App Clip targets.
[[[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);
}
}
}];
Kotlin+KTX Android
db.collection("cities")
.whereEqualTo("state", "CA")
.addSnapshotListener { snapshots, e ->
if (e != null) {
Log.w(TAG, "listen:error", e)
return@addSnapshotListener
}
for (dc in snapshots!!.documentChanges) {
when (dc.type) {
DocumentChange.Type.ADDED -> Log.d(TAG, "New city: ${dc.document.data}")
DocumentChange.Type.MODIFIED -> Log.d(TAG, "Modified city: ${dc.document.data}")
DocumentChange.Type.REMOVED -> Log.d(TAG, "Removed city: ${dc.document.data}")
}
}
}
Java 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;
}
}
}
});
Dart
db
.collection("cities")
.where("state", isEqualTo: "CA")
.snapshots()
.listen((event) {
for (var change in event.docChanges) {
switch (change.type) {
case DocumentChangeType.added:
print("New City: ${change.doc.data()}");
break;
case DocumentChangeType.modified:
print("Modified City: ${change.doc.data()}");
break;
case DocumentChangeType.removed:
print("Removed City: ${change.doc.data()}");
break;
}
}
});
C++
db->Collection("cities")
.WhereEqualTo("state", FieldValue::String("CA"))
.AddSnapshotListener([](const QuerySnapshot& snapshot, Error error, const std::string& errorMsg) {
if (error == Error::kErrorOk) {
for (const DocumentChange& dc : snapshot.DocumentChanges()) {
switch (dc.type()) {
case DocumentChange::Type::kAdded:
std::cout << "New city: "
<< dc.document().Get("name").string_value() << std::endl;
break;
case DocumentChange::Type::kModified:
std::cout << "Modified city: "
<< dc.document().Get("name").string_value() << std::endl;
break;
case DocumentChange::Type::kRemoved:
std::cout << "Removed city: "
<< dc.document().Get("name").string_value() << std::endl;
break;
}
}
} else {
std::cout << "Listen failed: " << error << std::endl;
}
});
PHP
// Not supported in the PHP client library
Unity
Query query = db.Collection("cities").WhereEqualTo("State", "CA");
ListenerRegistration listener = query.Listen(snapshot =>
{
foreach (DocumentChange change in snapshot.GetChanges())
{
if (change.ChangeType == DocumentChange.Type.Added)
{
Debug.Log(String.Format("New city: {0}", change.Document.Id));
}
else if (change.ChangeType == DocumentChange.Type.Modified)
{
Debug.Log(String.Format("Modified city: {0}", change.Document.Id));
}
else if (change.ChangeType == DocumentChange.Type.Removed)
{
Debug.Log(String.Format("Removed city: {0}", change.Document.Id));
}
}
});
Important: The first query snapshot contains added
events for all existing
documents that match the query. This is because you're getting a set of changes
that bring your query snapshot current with the initial state of the query. This
allows you, for instance, to directly populate your UI from the changes you
receive in the first query snapshot, without
needing to add special logic for handling the initial state.
The initial state can come from the server directly, or from a local
cache. If there is state available in a local cache, the query snapshot will
be initially populated with the cached data, then updated with the
server's data when the client has caught up with the server's state.
Detach a listener
When you are no longer interested in listening to your data, you must detach
your listener so that your event callbacks stop getting called. This allows the
client to stop using bandwidth to receive updates. For example:
Web version 9
Learn
more
about the tree-shakeable modular Web API and upgrade
from
the namespaced API.
import { collection, onSnapshot } from "firebase/firestore";
const unsubscribe = onSnapshot(collection(db, "cities"), () => {
// Respond to data
// ...
});
// Later ...
// Stop listening to changes
unsubscribe();
Web version 8
Learn
more
about the tree-shakeable modular Web API and upgrade
from
the namespaced API.
var unsubscribe = db.collection("cities")
.onSnapshot(() => {
// Respond to data
// ...
});
// Later ...
// Stop listening to changes
unsubscribe();
Swift
Note:
This product is not available on watchOS and App Clip targets.
let listener = db.collection("cities").addSnapshotListener { querySnapshot, error in
// ...
}
// ...
// Stop listening to changes
listener.remove()
Objective-C
Note:
This product is not available on watchOS and App Clip targets.
id<FIRListenerRegistration> listener = [[self.db collectionWithPath:@"cities"]
addSnapshotListener:^(FIRQuerySnapshot *snapshot, NSError *error) {
// ...
}];
// ...
// Stop listening to changes
[listener remove];
Kotlin+KTX Android
val query = db.collection("cities")
val registration = query.addSnapshotListener { snapshots, e ->
// ...
}
// ...
// Stop listening to changes
registration.remove()
Java Android
Query query = db.collection("cities");
ListenerRegistration registration = query.addSnapshotListener(
new EventListener<QuerySnapshot>() {
// ...
});
// ...
// Stop listening to changes
registration.remove();
Dart
final collection = db.collection("cities");
final listener = collection.snapshots().listen((event) {
// ...
});
listener.cancel();
C++
// Add a listener
Query query = db->Collection("cities");
ListenerRegistration registration = query.AddSnapshotListener(
[](const QuerySnapshot& snapshot, Error error, const std::string& errorMsg) { /* ... */ });
// Stop listening to changes
registration.Remove();
PHP
// Not supported in the PHP client library
Handle listen errors
A listen may occasionally fail — for example, due to security permissions, or if
you tried to listen on an invalid query. (Learn more about valid and invalid queries
.) To handle these
failures, you can provide an error callback when you attach your snapshot
listener. After an error, the listener will not receive any more events, and
there is no need to detach your listener.
Web version 9
Learn
more
about the tree-shakeable modular Web API and upgrade
from
the namespaced API.
import { collection, onSnapshot } from "firebase/firestore";
const unsubscribe = onSnapshot(
collection(db, "cities"),
(snapshot) => {
// ...
},
(error) => {
// ...
});
Web version 8
Learn
more
about the tree-shakeable modular Web API and upgrade
from
the namespaced API.
db.collection("cities")
.onSnapshot((snapshot) => {
// ...
}, (error) => {
// ...
});
Swift
Note:
This product is not available on watchOS and App Clip targets.
db.collection("cities")
.addSnapshotListener { querySnapshot, error in
if let error = error {
print("Error retreiving collection: \(error)")
}
}
Objective-C
Note:
This product is not available on watchOS and App Clip targets.
[[self.db collectionWithPath:@"cities"]
addSnapshotListener:^(FIRQuerySnapshot *snapshot, NSError *error) {
if (error != nil) {
NSLog(@"Error retreving collection: %@", error);
}
}];
Kotlin+KTX Android
db.collection("cities")
.addSnapshotListener { snapshots, e ->
if (e != null) {
Log.w(TAG, "listen:error", e)
return@addSnapshotListener
}
for (dc in snapshots!!.documentChanges) {
if (dc.type == DocumentChange.Type.ADDED) {
Log.d(TAG, "New city: ${dc.document.data}")
}
}
}
Java 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());
}
}
}
});
Dart
final docRef = db.collection("cities");
docRef.snapshots().listen(
(event) => print("listener attached"),
onError: (error) => print("Listen failed: $error"),
);
Python
// Snippet coming soon
C++
// Snippet coming soon.
PHP
// Not supported in the PHP client library
Unity
ListenerRegistration registration =
db.Collection("cities").Listen(
querySnapshot =>
{
// ...
});
registration.ListenerTask.ContinueWithOnMainThread(
listenerTask =>
{
if (listenerTask.IsFaulted)
{
Debug.LogError($"Listen failed: {listenerTask.Exception}");
// ...
// Handle the listener error.
// ...
}
});
C#
// Snippet coming soon
What's next
Send feedback
Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 License
, and code samples are licensed under the Apache 2.0 License
. For details, see the Google Developers Site Policies
. Java is a registered trademark of Oracle and/or its affiliates.
Last updated 2024-09-26 UTC.
[{
"type": "thumb-down",
"id": "hardToUnderstand",
"label":"Hard to understand"
},{
"type": "thumb-down",
"id": "incorrectInformationOrSampleCode",
"label":"Incorrect information or sample code"
},{
"type": "thumb-down",
"id": "missingTheInformationSamplesINeed",
"label":"Missing the information/samples I need"
},{
"type": "thumb-down",
"id": "otherDown",
"label":"Other"
}]
[{
"type": "thumb-up",
"id": "easyToUnderstand",
"label":"Easy to understand"
},{
"type": "thumb-up",
"id": "solvedMyProblem",
"label":"Solved my problem"
},{
"type": "thumb-up",
"id": "otherUp",
"label":"Other"
}]
Need to tell us more?
{"lastModified": "Last updated 2024-09-26 UTC."}
[[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Hard to understand","hardToUnderstand","thumb-down"],["Incorrect information or sample code","incorrectInformationOrSampleCode","thumb-down"],["Missing the information/samples I need","missingTheInformationSamplesINeed","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2024-09-26 UTC."]]