0

I'm struggling to get or find out which document got changed when listening to a collection in the Firestore database.

 Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", certificatePath);
            FirestoreDb db = FirestoreDb.Create("myapp-123");
            CollectionReference collection = db.Collection("customers");
           
            FirestoreChangeListener listener = collection.Listen(snapshot =>
            {
                Console.WriteLine($"Callback received document snapshot");
                Console.WriteLine();
            }); 
            await listener.ListenerTask;

When I make changes to any document in the collection, they are detected as expected but I don't know how to get the document that was changed.

How can I get find which document was changed as well as fetch its new values?

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
West
  • 2,350
  • 5
  • 31
  • 67

2 Answers2

2

To find out what document(s) changed between snapshots, loop over the Changes collection instead of the Documents collection:

From the linked documentation:

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);
        }
    }
});
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
1

To know which document is changed in Firestore, for example, by their ID, please use the following lines of code:

FirestoreDb db = FirestoreDb.Create("myapp-123");
CollectionReference customersRef = db.Collection("customers");

FirestoreChangeListener listener = customersRef.Listen(snapshot =>
{
    Console.WriteLine("Customer IDs:");
    foreach (DocumentSnapshot documentSnapshot in snapshot.Documents)
    {
        Console.WriteLine(documentSnapshot.Id);
    }
});

Please also note, that the snapshot handler will receive a new snapshot every time the query results change (that is when a document is added, removed, or updated).

Edit:

According to your comment:

it just prints out everything

That's the expected behavior since when you attach a snapshot listener to get updates in real-time, you are getting at the beginning all documents that satisfy the corresponding query. Unfortunately, there is no way you can change that. There is a workaround, however, which is explained in my answer from the following post:

How to skip initial data and trigger only new updates in Firestore Firebase?

Where you can see the actual changes to query results between query snapshots:

FirestoreDb db = FirestoreDb.Create("myapp-123");
CollectionReference customersRef = db.Collection("customers");
FirestoreChangeListener listener = customersRef.Listen(snapshot =>
{
    foreach (DocumentChange change in snapshot.Changes)
    {
        if (change.ChangeType.ToString() == "Added")
        {
            Console.WriteLine("New customer: {0}", change.Document.Id);
        }
        else if (change.ChangeType.ToString() == "Modified")
        {
            Console.WriteLine("Modified customer: {0}", change.Document.Id);
        }
        else if (change.ChangeType.ToString() == "Removed")
        {
            Console.WriteLine("Removed customer: {0}", change.Document.Id);
        }
    }
});

But please remember that you cannot skip the "Added" case.

Also, since it's printing out everything every time a small change is made, does it mean if I have 100k documents I'll be getting charged for at least 100k reads whenever the listener fires?

No, it prints everything the first time you attach the listener and not at every change. Once you get all the documents that satisfy the query, you are only getting the documents that satisfy a particular case. However, if you have 100k documents in your collection, first lime you attach a listener you'll be billed with 100k reads. That's why you should consider implementing filters, or pagination.

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
  • I did try this earlier and it just prints out everything and nothing shows which document changed. Also, since its printing out everything everytime a small change is made, does it mean if I have 100k documents I'll be getting charged for at least 100k reads whenever the listener fires? – West Aug 11 '21 at 01:58
  • No, it doesn't please. See my updated answer. Is it clear now? – Alex Mamo Aug 11 '21 at 05:50
  • Thanks all understood now. Maybe I must have misunderstood your initial answer but what I meant was that the line `Console.WriteLine(documentSnapshot.Id);` was printing out every id in the database no matter if it was first time listening or subsequent changes. Therefore there was no way for me to tell what had been changed jus with that code. – West Aug 11 '21 at 06:00