I have a food app with a star system. Every time a user selects a rating/star I send their rating to the database and then run a firebase transaction to update the total amount of users who left a rating.
let theirRating: Double = // whatEverStarRatingTheySelected
let dict = [currentUserId: theirRating]
let reviewsRef = Database.database().reference().child("reviews").child(postId)
reviewsRef.updateChildValues(dict) { (error, ref) in
    let postsRef = Database.database().reference().child("posts").child(postId).child("totalUsersCount")
    postsRef.runTransactionBlock({ (mutableData: MutableData) -> TransactionResult in
        // ...
    })
}
When displaying the actual rating I pull the the post which has the totalUsersCount as a property, I pull all of the users actual ratings, add them all together, and then feed both numbers into an algo to spit out the actual rating. I do all of this on the client. How can I do the same thing "I pull all of the users actual rating, add them all together" with a Cloud Function, that is similar to this answer?
Database.database().reference().child("posts").child(postId).observeSingleEvent(of: .value, with: { (snapshot) in
 
     guard let dict = snapshot.value as? [String:Any] else { return }
     let post = Post(dict: dict)
 
     let totalUsers = post.totalUsersCount
     Database.database().reference().child("reviews").child(postId).observeSingleEvent(of: .value, with: { (snapshot) in
      
          var ratingSum = 0.0
      
          // *** how can I do this part using a Cloud Function so that way I can just read this number as a property on the post instead of doing all of this on the client ***
          for review in (snapshot.children.allObjects as! [DataSnapshot]) {
              guard let rating = review.value as? Double else { continue }
              ratingSum += rating
          }
      
          let starRatingToDisplay = self.algoToComputeStarRating(totalUsersCount: totalUsersCount, ratingsSum: ratingSum)
     })
 })
This isn't a question about the algoToComputeStarRating, that I can do on the client. I want to add all of the user's ratings together using a Cloud Function, then just add that result as a property to the post. That way when I pull the post all I have to do is:
Database.database().reference().child("posts").child(postId).observeSingleEvent(of: .value, with: { (snapshot) in
    guard let dict = snapshot.value as? [String:Any] else { return }
    let post = Post(dict: dict)
         
    let totalUsersCount = post.totalUsersCount
    let ratingsSum = post.ratingsSum
    
    let starRatingToDisplay = self.algoToComputeStarRating(totalUsersCount: totalUsersCount, ratingsSum: ratingSum)
})
Database structure:
@posts
   @postId
      -postId: "..."
      -userId: "..."
      -totalUsersCount: 22
      -ratingsSum: 75 // this should be the result from the cloud function
@reviews
    @postId
       -uid_1: theirRating
       -uid_2: theirRating
       // ...
       -uid_22: theirRating
This is what I tried so far:
exports.calculateTotalRating = functions.https.onRequest((data, response) => {
    const postId = data.postId;
    
    const totalUsersCtRef = admin.database().ref('/posts/' + postId + '/' + 'totalUsersCt');
    const postsRef = admin.database().ref('/posts/' + postId);
    admin.database().ref('reviews').child(postId).once('value', snapshot => {
        if (snapshot.exists()) {
            var ratingsSum = 0.0;
            snapshot.forEach(function(child) {
                ratingsSum += child().val()
            })
            .then(() => { 
            
                return postsRef.set({ "ratingsSum": ratingsSum})          
            })
            .then(() => { 
            
                return totalUsersCtRef.set(admin.database.ServerValue.increment(1));                
            }) 
            .catch((error) => {
                console.log('ERROR - calculateTotalRating() Failed: ', error);
            });
        }
    });
});
 
    