Consider the following simple Firestore structure:
db/posts/{postId}/comments/{commentId}A post document contains the fields
---------POST---------A comment document contains the fields
--------COMMENT---------Current solution
When a user posts a comment from the client app, they do so using the Firestore SDK (for Flutter in my case) directly into Firestore.
db.col("posts").doc(postId).col("comments").doc() .set({ comment:"Hello there!" })I have written Firestore Rules to validate certain field in the new comment doc
match /posts/{postId}/comments/{commentId}{ allow create: if request.resource.data.text.size() < 100 }When this document gets passed by the rules and added, a cloud function triggers, which increments the comment_count of the post
exports.onCommentCreate = functions.firestore.document("posts/{postId}/comments/{commentId}") .onCreate(async (snap, context) => { db.col("posts").doc(postId) .update({ "comment_count": admin.firestore.FieldValue.increment(1) }); });When a comment document is removed, another cloud function triggers, which decrements the comment_count of the post
Problem
If any cloud functions fail after a comment document has been added directly by the client, such as the one that increments the comment_count on the post document, the comment doc which was added by the user will remain, even though the comment hasn't been "registered" properly. This means that our database may become unsynced, which is bad.
A fix to this would be catch the functions errors, and delete the comment doc which was added in the same function if something goes wrong. That would sync everything, however, it would cause other problems such as the decrement function now being triggered (as the failing function removed the comment) which would result in comment_count being -1. Also, I have no way of responding to the user with an error
Proposed solution
A proposed solution to this could be to let clients add comments using a Callable Cloud function instead of adding directly to the database. Suppose I have the following function:
exports.addComment = functions.https.onCall(async (data, context) => {This solution...
A similar function would be written for deleting the comment as well, which has the same benefits
Questions
The questions I would like answers to are:
Sorry for a long text, I tried my best to simplify and organize things :) Any response would be greatly appreciated!