0

I have a case where I need to update a field of all of the documents in a collection, and I am doing this with the batch update, however, the approach that I am using at the moment is first making me read all of the documents, and that is not necessary.

I just want to update my users collection, all users have a field called credits and I want to use that function to reset everyone's credits, and this works:

const usersRef = await firebaseAdmin.firestore().collection("users").get();

const batchCreditsReset = firebaseAdmin.firestore().batch();

usersRef.docs.forEach(doc => {
  batchCreditsReset.update(doc.ref, { credits: 1000 });
});

await batchCreditsReset.commit();

But how do I do this without first reading the whole collection? I don't need to read it as I already know what I want to set the values to and that does not depend on any current values.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
Darkbound
  • 3,026
  • 7
  • 34
  • 72

1 Answers1

1

There is no need to read a document in order to update it. What you have to do, is to create a reference that points exactly to that document and then call update(). This means that you have to know the document ID ahead of time in order to perform an update.

When it comes to Admin SDK, please note that it is allowed to specify which fields you want with select(). The name of the function may vary from one programming language to another.

If you are using, for example, Node.js, please check the answer below:

If you however need to update an entire collection from the client SDKs, then you have to know the IDs of all existing documents before performing the updates. You can do that either by reading all documents, extracting the IDs, and performing the update, or you can store all document IDs in a document, in a field of type array. To update all documents, you only have to read a single document, create the document references and perform the update. In this way, you'll only have to pay for a single read and not for a number of reads that is equal to the number of documents that exist in your collection. This solution will work with a collection that contains a reasonable number of documents.

So if you decide to use the solution above, be aware that there are some limits when it comes to how much data you can put into a document. According to the official documentation regarding usage and limits:

Maximum size for a document: 1 MiB (1,048,576 bytes)

As you can see, you are limited to 1 MiB total of data in a single document. When we are talking about storing strings (document IDs), you can store pretty much. I doubt you'll reach the limitation but as your arrays get bigger, be careful about this constraint. One more thing to remember is that you always have to keep the document up to date, meaning that if a document is added to the collection, you have to update the array with the new ID, the same when you delete a document. The simplest solution for that would be to use Cloud Functions for Firebase.

A workaround for this would be to store the document IDs in the Firebase Realtime Database, which has a different type of billing mechanism. There are no reads involved there.

So it's up to you to decide which solution works best for your application.

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
  • Hey Darkbound. Did my answer help? Can I help you with other information? – Alex Mamo Feb 25 '23 at 08:40
  • 1
    The solution makes sense Alex. Hopefully we will in future be able to either i) have a cost effective query that only gets document Ids and not the fields or ii) perform server side updates on batch documents based upon a query that also and only runs server-side. Goal of course is to reduce cost in exchange for return data that wouldn't be needed. – Mabz Aug 14 '23 at 16:17