Ricevi aggiornamenti in tempo reale con Cloud Firestore

È possibile ascoltare un documento con l' onSnapshot() metodo. Una chiamata iniziale utilizzando la richiamata si fornisce crea un'istantanea documento immediatamente con il contenuto corrente del documento unico. Poi, ogni volta che i contenuti cambiano, un'altra chiamata aggiorna l'istantanea documento.

Web version 9

import { doc, onSnapshot } from "firebase/firestore";

const unsub = onSnapshot(doc(db, "cities", "SF"), (doc) => {
    console.log("Current data: ", doc.data());
});

Web version 8

db.collection("cities").doc("SF")
    .onSnapshot((doc) => {
        console.log("Current data: ", doc.data());
    });
veloce
Nota: Questo prodotto non è disponibile su obiettivi clip watchos e App.
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
Nota: Questo prodotto non è disponibile su obiettivi clip watchos e App.
[[[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);
    }];

Java

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

Kotlin+KTX

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

Dart

final docRef = db.collection("cities").doc("SF");
docRef.snapshots().listen(
      (event) => print("current data: ${event.data()}"),
      onError: (error) => print("Listen failed: $error"),
    );

Spesso, si desidera che l'interfaccia utente per reagire ai cambiamenti nei contenuti di un documento FireStore o la raccolta. È possibile farlo con un StreamBuilder widget che consuma il FireStore snapshot flusso:

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(),
        );
      },
    );
  }
}
Giava
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");
        }
      }
    });
Pitone

# Create an Event for notifying main thread.
callback_done = threading.Event()

# Create a callback on_snapshot function to capture changes
def on_snapshot(doc_snapshot, changes, read_time):
    for doc in doc_snapshot:
        print(f'Received document snapshot: {doc.id}')
    callback_done.set()

doc_ref = db.collection(u'cities').document(u'SF')

# Watch the document
doc_watch = doc_ref.on_snapshot(on_snapshot)
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;
      }
    });
Node.js
const doc = db.collection('cities').doc('SF');

const observer = doc.onSnapshot(docSnapshot => {
  console.log(`Received doc snapshot: ${docSnapshot}`);
  // ...
}, err => {
  console.log(`Encountered error: ${err}`);
});
andare
import (
	"context"
	"fmt"
	"io"
	"time"

	"cloud.google.com/go/firestore"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

// listenDocument listens to a single document.
func listenDocument(ctx context.Context, w io.Writer, projectID, collection string) error {
	// projectID := "project-id"
	// Сontext with timeout stops listening to changes.
	ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
	defer cancel()

	client, err := firestore.NewClient(ctx, projectID)
	if err != nil {
		return fmt.Errorf("firestore.NewClient: %v", err)
	}
	defer client.Close()

	it := client.Collection(collection).Doc("SF").Snapshots(ctx)
	for {
		snap, err := it.Next()
		// DeadlineExceeded will be returned when ctx is cancelled.
		if status.Code(err) == codes.DeadlineExceeded {
			return nil
		}
		if err != nil {
			return fmt.Errorf("Snapshots.Next: %v", err)
		}
		if !snap.Exists() {
			fmt.Fprintf(w, "Document no longer exists\n")
			return nil
		}
		fmt.Fprintf(w, "Received document snapshot: %v\n", snap.Data())
	}
}
PHP
// Not supported in the PHP client library
Unità
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));
    }
});
C#
DocumentReference docRef = db.Collection("cities").Document("SF");
FirestoreChangeListener listener = docRef.Listen(snapshot =>
{
    Console.WriteLine("Callback received document snapshot.");
    Console.WriteLine("Document exists? {0}", snapshot.Exists);
    if (snapshot.Exists)
    {
        Console.WriteLine("Document data for {0} document:", snapshot.Id);
        Dictionary<string, object> city = snapshot.ToDictionary();
        foreach (KeyValuePair<string, object> pair in city)
        {
            Console.WriteLine("{0}: {1}", pair.Key, pair.Value);
        }
    }
});
Rubino
doc_ref = firestore.col(collection_path).doc document_path
snapshots = []

# Watch the document.
listener = doc_ref.listen do |snapshot|
  puts "Received document snapshot: #{snapshot.document_id}"
  snapshots << snapshot
end

Eventi per modifiche locali

scrive locali nella vostra applicazione sarà richiamare immediatamente gli ascoltatori di snapshot. Questo è causa di una caratteristica importante chiamata "compensazione di latenza." Quando si esegue una scrittura, gli ascoltatori saranno informati con i nuovi dati prima che i dati vengono inviati al backend.

Documenti recuperati hanno un metadata.hasPendingWrites proprietà che indica se il documento contiene modifiche locali che non sono state scritte per il backend ancora. È possibile utilizzare questa proprietà per determinare l'origine degli eventi ricevuti dal vostro ascoltatore snapshot:

Web version 9

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

db.collection("cities").doc("SF")
    .onSnapshot((doc) => {
        var source = doc.metadata.hasPendingWrites ? "Local" : "Server";
        console.log(source, " data: ", doc.data());
    });
veloce
Nota: Questo prodotto non è disponibile su obiettivi clip watchos e App.
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
Nota: Questo prodotto non è disponibile su obiettivi clip watchos e App.
[[[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);
    }];

Java

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

Kotlin+KTX

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

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"),
);
Giava
# Not yet supported in the Java client library
Pitone
// 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
andare
// Not yet supported in the Go client library
PHP
// Not supported in the PHP client library
Unità
// Not yet supported in the Unity SDK
C#
// Not yet supported in the C# client library
Rubino
// Not yet supported in the Ruby client library

Eventi per le modifiche dei metadati

Durante l'ascolto per le modifiche a un documento, la raccolta, o una query, si può passare opzioni per controllare la granularità degli eventi che riceverà il vostro ascoltatore.

Per impostazione predefinita, gli ascoltatori non vengono informati dei cambiamenti che interessano solo i metadati. Si consideri che cosa accade quando la vostra applicazione scrive un nuovo documento:

  1. Un evento di modifica viene immediatamente licenziato con i nuovi dati. Il documento non è ancora stato scritto il backend in modo che il flag "scrive in sospeso" è true .
  2. Il documento è stato scritto per il backend.
  3. Il backend notifica al client della scrittura di successo. Non ci sono cambiamenti ai dati del documento, ma v'è un cambiamento dei metadati perché la bandiera "scrive in sospeso" è ora false .

Se si desidera ricevere snapshot eventi quando il documento o di query modifiche ai metadati, passano un ascoltano opzioni oggetto quando si collega il vostro ascoltatore:

Web version 9

import { doc, onSnapshot } from "firebase/firestore";

const unsub = onSnapshot(
  doc(db, "cities", "SF"), 
  { includeMetadataChanges: true }, 
  (doc) => {
    // ...
  });

Web version 8

db.collection("cities").doc("SF")
    .onSnapshot({
        // Listen for document metadata changes
        includeMetadataChanges: true
    }, (doc) => {
        // ...
    });
veloce
Nota: Questo prodotto non è disponibile su obiettivi clip watchos e App.
// Listen to document metadata.
db.collection("cities").document("SF")
    .addSnapshotListener(includeMetadataChanges: true) { documentSnapshot, error in
        // ...
    }
Objective-C
Nota: Questo prodotto non è disponibile su obiettivi clip watchos e App.
// Listen for metadata changes.
[[[self.db collectionWithPath:@"cities"] documentWithPath:@"SF"]
    addSnapshotListenerWithIncludeMetadataChanges:YES
                                         listener:^(FIRDocumentSnapshot *snapshot, NSError *error) {
   // ...
}];

Java

// 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) {
        // ...
    }
});

Kotlin+KTX

// Listen for metadata changes to the document.
val docRef = db.collection("cities").document("SF")
docRef.addSnapshotListener(MetadataChanges.INCLUDE) { snapshot, e ->
    // ...
}

Dart

final docRef = db.collection("cities").doc("SF");
docRef.snapshots(includeMetadataChanges: true).listen((event) {
  // ...
});
Giava
// Not yet supported in the Java client library
Pitone
// 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
andare
// Not yet supported in the Go client library
PHP
// Not supported in the PHP client library
Unità
// Not yet supported in the Unity SDK
C#
// Not yet supported in the C# client library
Rubino
// Not yet supported in the Ruby client library

Ascoltate più documenti in una raccolta

Come con i documenti, è possibile utilizzare onSnapshot() al posto di get() per ascoltare i risultati di una query. Questo crea uno snapshot query. Ad esempio, per ascoltare i documenti con stato di CA :

Web version 9

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

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(", "));
    });
veloce
Nota: Questo prodotto non è disponibile su obiettivi clip watchos e App.
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
Nota: Questo prodotto non è disponibile su obiettivi clip watchos e App.
[[[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);
    }];

Java

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

Kotlin+KTX

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

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(", ")}");
});
Giava
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);
          }
        });
Pitone

# Create an Event for notifying main thread.
callback_done = threading.Event()

# Create a callback on_snapshot function to capture changes
def on_snapshot(col_snapshot, changes, read_time):
    print(u'Callback received query snapshot.')
    print(u'Current cities in California:')
    for doc in col_snapshot:
        print(f'{doc.id}')
    callback_done.set()

col_query = db.collection(u'cities').where(u'state', u'==', u'CA')

# Watch the collection query
query_watch = col_query.on_snapshot(on_snapshot)
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;
      }
    });
Node.js
const query = db.collection('cities').where('state', '==', 'CA');

const observer = query.onSnapshot(querySnapshot => {
  console.log(`Received query snapshot of size ${querySnapshot.size}`);
  // ...
}, err => {
  console.log(`Encountered error: ${err}`);
});
andare
import (
	"context"
	"fmt"
	"io"
	"time"

	"cloud.google.com/go/firestore"
	"google.golang.org/api/iterator"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

// listenMultiple listens to a query, returning the names of all cities
// for a state.
func listenMultiple(ctx context.Context, w io.Writer, projectID, collection string) error {
	// projectID := "project-id"
	ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
	defer cancel()

	client, err := firestore.NewClient(ctx, projectID)
	if err != nil {
		return fmt.Errorf("firestore.NewClient: %v", err)
	}
	defer client.Close()

	it := client.Collection(collection).Where("state", "==", "CA").Snapshots(ctx)
	for {
		snap, err := it.Next()
		// DeadlineExceeded will be returned when ctx is cancelled.
		if status.Code(err) == codes.DeadlineExceeded {
			return nil
		}
		if err != nil {
			return fmt.Errorf("Snapshots.Next: %v", err)
		}
		if snap != nil {
			for {
				doc, err := snap.Documents.Next()
				if err == iterator.Done {
					break
				}
				if err != nil {
					return fmt.Errorf("Documents.Next: %v", err)
				}
				fmt.Fprintf(w, "Current cities in California: %v\n", doc.Ref.ID)
			}
		}
	}
}
PHP
// Not supported in the PHP client library
Unità
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);
  }
});
C#
CollectionReference citiesRef = db.Collection("cities");
Query query = db.Collection("cities").WhereEqualTo("State", "CA");

FirestoreChangeListener listener = query.Listen(snapshot =>
{
    Console.WriteLine("Callback received query snapshot.");
    Console.WriteLine("Current cities in California:");
    foreach (DocumentSnapshot documentSnapshot in snapshot.Documents)
    {
        Console.WriteLine(documentSnapshot.Id);
    }
});
Rubino
query = firestore.col(collection_path).where :state, :==, "CA"
docs = []

# Watch the collection query.
listener = query.listen do |snapshot|
  puts "Callback received query snapshot."
  puts "Current cities in California:"
  snapshot.docs.each do |doc|
    puts doc.document_id
    docs << doc
  end
end

Il gestore snapshot riceverà una nuova query snapshot ogni volta che il cambiamento risultati della query (cioè, quando si aggiunge un documento, rimosso o modificato).

Vista cambia tra le istantanee

Spesso è utile vedere i cambiamenti effettivi risultati dell'interrogazione tra istantanee di query, invece di usare l'intera istantanea query. Ad esempio, si può decidere di mantenere una cache quando vengono aggiunti singoli documenti, rimossi, e modificati.

Web version 9

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

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());
            }
        });
    });
veloce
Nota: Questo prodotto non è disponibile su obiettivi clip watchos e App.
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
Nota: Questo prodotto non è disponibile su obiettivi clip watchos e App.
[[[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);
        }
      }
    }];

Java

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

            }
        });

Kotlin+KTX

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

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;
    }
  }
});
Giava
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;
              }
            }
          }
        });
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;
      }
    });
Pitone

# Create an Event for notifying main thread.
delete_done = threading.Event()

# Create a callback on_snapshot function to capture changes
def on_snapshot(col_snapshot, changes, read_time):
    print(u'Callback received query snapshot.')
    print(u'Current cities in California: ')
    for change in changes:
        if change.type.name == 'ADDED':
            print(f'New city: {change.document.id}')
        elif change.type.name == 'MODIFIED':
            print(f'Modified city: {change.document.id}')
        elif change.type.name == 'REMOVED':
            print(f'Removed city: {change.document.id}')
            delete_done.set()

col_query = db.collection(u'cities').where(u'state', u'==', u'CA')

# Watch the collection query
query_watch = col_query.on_snapshot(on_snapshot)
Node.js
const observer = db.collection('cities').where('state', '==', 'CA')
  .onSnapshot(querySnapshot => {
    querySnapshot.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());
      }
    });
  });
andare
import (
	"context"
	"fmt"
	"io"
	"time"

	"cloud.google.com/go/firestore"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

// listenChanges listens to a query, returning the list of document changes.
func listenChanges(ctx context.Context, w io.Writer, projectID, collection string) error {
	// projectID := "project-id"
	ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
	defer cancel()

	client, err := firestore.NewClient(ctx, projectID)
	if err != nil {
		return fmt.Errorf("firestore.NewClient: %v", err)
	}
	defer client.Close()

	it := client.Collection(collection).Where("state", "==", "CA").Snapshots(ctx)
	for {
		snap, err := it.Next()
		// DeadlineExceeded will be returned when ctx is cancelled.
		if status.Code(err) == codes.DeadlineExceeded {
			return nil
		}
		if err != nil {
			return fmt.Errorf("Snapshots.Next: %v", err)
		}
		if snap != nil {
			for _, change := range snap.Changes {
				switch change.Kind {
				case firestore.DocumentAdded:
					fmt.Fprintf(w, "New city: %v\n", change.Doc.Data())
				case firestore.DocumentModified:
					fmt.Fprintf(w, "Modified city: %v\n", change.Doc.Data())
				case firestore.DocumentRemoved:
					fmt.Fprintf(w, "Removed city: %v\n", change.Doc.Data())
				}
			}
		}
	}
}
PHP
// Not supported in the PHP client library
Unità
        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));
                }
            }
        });
    }
}
C#
CollectionReference citiesRef = db.Collection("cities");
Query query = db.Collection("cities").WhereEqualTo("State", "CA");

FirestoreChangeListener listener = query.Listen(snapshot =>
{
    foreach (DocumentChange change in snapshot.Changes)
    {
        if (change.ChangeType.ToString() == "Added")
        {
            Console.WriteLine("New city: {0}", change.Document.Id);
        }
        else if (change.ChangeType.ToString() == "Modified")
        {
            Console.WriteLine("Modified city: {0}", change.Document.Id);
        }
        else if (change.ChangeType.ToString() == "Removed")
        {
            Console.WriteLine("Removed city: {0}", change.Document.Id);
        }
    }
});
Rubino
query = firestore.col(collection_path).where :state, :==, "CA"
added = []
modified = []
removed = []

# Watch the collection query.
listener = query.listen do |snapshot|
  puts "Callback received query snapshot."
  puts "Current cities in California:"
  snapshot.changes.each do |change|
    if change.added?
      puts "New city: #{change.doc.document_id}"
      added << snapshot
    elsif change.modified?
      puts "Modified city: #{change.doc.document_id}"
      modified << snapshot
    elsif change.removed?
      puts "Removed city: #{change.doc.document_id}"
      removed << snapshot
    end
  end
end

Lo stato iniziale può venire dal server direttamente, o da una cache locale. Se v'è stato disponibile in una cache locale, l'istantanea di query sarà inizialmente popolata con i dati memorizzati nella cache, quindi aggiornati con i dati del server quando il client ha raggiunto con lo stato del server.

Staccare un ascoltatore

Quando si è più interessato ad ascoltare i vostri dati, è necessario staccare il vostro ascoltatore in modo che i callback di evento non ottenere chiamato. Questo permette al cliente di smettere di usare la larghezza di banda per ricevere gli aggiornamenti. Per esempio:

Web version 9

import { collection, onSnapshot } from "firebase/firestore";

const unsubscribe = onSnapshot(collection(db, "cities"), () => {
  // Respond to data
  // ...
});

// Later ...

// Stop listening to changes
unsubscribe();

Web version 8

var unsubscribe = db.collection("cities")
    .onSnapshot(() => {
      // Respond to data
      // ...
    });

// Later ...

// Stop listening to changes
unsubscribe();
veloce
Nota: Questo prodotto non è disponibile su obiettivi clip watchos e App.
let listener = db.collection("cities").addSnapshotListener { querySnapshot, error in
    // ...
}

// ...

// Stop listening to changes
listener.remove()
Objective-C
Nota: Questo prodotto non è disponibile su obiettivi clip watchos e App.
id<FIRListenerRegistration> listener = [[self.db collectionWithPath:@"cities"]
    addSnapshotListener:^(FIRQuerySnapshot *snapshot, NSError *error) {
      // ...
}];

// ...

// Stop listening to changes
[listener remove];

Java

Query query = db.collection("cities");
ListenerRegistration registration = query.addSnapshotListener(
        new EventListener<QuerySnapshot>() {
            // ...
        });

// ...

// Stop listening to changes
registration.remove();

Kotlin+KTX

val query = db.collection("cities")
val registration = query.addSnapshotListener { snapshots, e ->
    // ...
}

// ...

// Stop listening to changes
registration.remove()

Dart

final collection = db.collection("cities");
final listener = collection.snapshots().listen((event) {
  // ...
});
listener.cancel();
Giava
Query query = db.collection("cities");
ListenerRegistration registration =
    query.addSnapshotListener(
        new EventListener<QuerySnapshot>() {
          // ...
        });

// ...

// Stop listening to changes
registration.remove();
Pitone
# Terminate watch on a document
doc_watch.unsubscribe()
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();
Node.js
const unsub = db.collection('cities').onSnapshot(() => {
});

// ...

// Stop listening for changes
unsub();
andare
// Сontext with timeout stops listening to changes.
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
PHP
// Not supported in the PHP client library
Unità
listener.Stop();
C#
await listener.StopAsync();
Rubino
listener.stop

Maniglia ascoltare errori

Un ascolto può occasionalmente fallire - per esempio, a causa di autorizzazioni di protezione, o se si è tentato di ascolto su una query non valida. (Ulteriori informazioni sulle query valide e non valide .) Per gestire questi errori, è possibile fornire un callback di errore quando si collega il vostro ascoltatore snapshot. Dopo un errore, l'ascoltatore non riceverai più eventi, e non v'è alcuna necessità di staccare il vostro ascoltatore.

Web version 9

import { collection, onSnapshot } from "firebase/firestore";

const unsubscribe = onSnapshot(
  collection(db, "cities"), 
  (snapshot) => {
    // ...
  },
  (error) => {
    // ...
  });

Web version 8

db.collection("cities")
    .onSnapshot((snapshot) => {
        // ...
    }, (error) => {
        // ...
    });
veloce
Nota: Questo prodotto non è disponibile su obiettivi clip watchos e App.
db.collection("cities")
    .addSnapshotListener { querySnapshot, error in
        if let error = error {
            print("Error retreiving collection: \(error)")
        }
    }
Objective-C
Nota: Questo prodotto non è disponibile su obiettivi clip watchos e App.
[[self.db collectionWithPath:@"cities"]
    addSnapshotListener:^(FIRQuerySnapshot *snapshot, NSError *error) {
      if (error != nil) {
        NSLog(@"Error retreving collection: %@", error);
      }
    }];

Java

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

            }
        });

Kotlin+KTX

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

Dart

final docRef = db.collection("cities");
docRef.snapshots().listen(
      (event) => print("listener attached"),
      onError: (error) => print("Listen failed: $error"),
    );
Giava
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());
              }
            }
          }
        });
Pitone
// Snippet coming soon
C ++
// Snippet coming soon.
Node.js
db.collection('cities')
  .onSnapshot((snapshot) => {
    //...
  }, (error) => {
    //...
  });
andare
import (
	"context"
	"fmt"
	"io"
	"time"

	"cloud.google.com/go/firestore"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

// listenErrors demonstrates how to handle listening errors.
func listenErrors(ctx context.Context, w io.Writer, projectID, collection string) error {
	// projectID := "project-id"
	ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
	defer cancel()

	client, err := firestore.NewClient(ctx, projectID)
	if err != nil {
		return fmt.Errorf("firestore.NewClient: %v", err)
	}
	defer client.Close()

	it := client.Collection(collection).Snapshots(ctx)
	for {
		snap, err := it.Next()
		// Canceled will be returned when ctx is cancelled and DeadlineExceeded will
		// be returned when ctx reaches its deadline.
		if e := status.Code(err); e == codes.Canceled || e == codes.DeadlineExceeded {
			return nil
		}
		if err != nil {
			return fmt.Errorf("Snapshots.Next: %v", err)
		}
		if snap != nil {
			for _, change := range snap.Changes {
				if change.Kind == firestore.DocumentAdded {
					fmt.Fprintf(w, "New city: %v\n", change.Doc.Data())
				}
			}
		}
	}
}
PHP
// Not supported in the PHP client library
Unità
// Not supported in the Unity SDK.
C#
// Snippet coming soon
Rubino
listener = firestore.col(collection_path).listen do |snapshot|
  snapshot.changes.each do |change|
    puts "New city: #{change.doc.document_id}" if change.added?
  end
end

# Register to be notified when unhandled errors occur.
listener.on_error do |error|
  puts "Listen failed: #{error.message}"
end

Qual è il prossimo