How to update a value in multiples collections at once in firestore?

Tags: , , ,



I’m building a forum appin Vue, basically a clone of this same site… The user can post questions, get answers to those questions and comments to those answers. I have a top level collection for questions, answers and comments respectively, and each document in those collections have a field called photoURL where I store the url of the profile image of the author of that question/answer/comment.

Now, I have this code to update the photoURL field in each document from the same author in the three collections when a user update their profile image:

const QUESTIONS = db.collection("questions");
QUESTIONS.where("authorId", "==", this.user.data.id)
.get()
.then(snapshots => {
    if (snapshots.size > 0) {
        snapshots.forEach(questionItem => {
            QUESTIONS.doc(questionItem.id).update({
                photoURL: imgUrl
            });
        });
    }
});

const ANSWERS = db.collection("answers");
ANSWERS.where("authorId", "==", this.user.data.id)
.get()
.then(snapshots => {
    if (snapshots.size > 0) {
        snapshots.forEach(answerItem => {
            ANSWERS.doc(answerItem.id).update({
                photoURL: imgUrl
            });
        });
    }
});

const COMMENTS = db.collection("comments");
COMMENTS.where("authorId", "==", this.user.data.id)
.get()
.then(snapshots => {
    if (snapshots.size > 0) {
        snapshots.forEach(commentItem => {
            COMMENTS.doc(commentItem.id).update({
                photoURL: imgUrl
            });
        });
    }
});

It currently works, but there is a way to make these three operations at once? Or a better way in general to achieve those updates? I was thinking in storing all the ids retrieved from the three collections in an array first and then make the updates, but the numbers of writes would remain the same, so it doesn’t looks like an improve.

Answer

Two approaches I can quickly think of:

  1. Reduce the amount of duplicated code.
  2. Change the data model.

Reduce the amount of duplicated code

You can create a helper function that takes the collection to update as an argument:

function updateDocumentsInCollectionForAuthor(collection, author, update) {
  db.collection(collection).where("authorId", "==", author)
    .get()
    .then(snapshots => {
      snapshots.forEach(doc => {
        doc.ref.update(update);
      });
    });
}

As Doug said, you could do this in batches, but the performance difference likely isn’t worth the code complexity as shown here: What is the fastest way to write a lot of documents to Firestore?

Then you can call it to update each collection:

updateDocumentsInCollectionForAuthor("questions", this.user.data.id, { photoURL: imgUrl });
updateDocumentsInCollectionForAuthor("answers", this.user.data.id, { photoURL: imgUrl });
updateDocumentsInCollectionForAuthor("comments", this.user.data.id, { photoURL: imgUrl });

Change the data model

The alternative is to change your data model to store all questions, answers, and comments in the same collection. That is actually what Stack Overflow does: all these items are in a single table, and set apart by a value indicating the type of post it is.



Source: stackoverflow