【发布时间】:2021-05-06 16:41:54
【问题描述】:
我有一个带有星级系统的美食应用。每次用户选择评分/星级时,我都会将他们的评分发送到数据库,然后运行 firebase transaction 来更新留下评分的用户总数。
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
// ...
})
}
在显示实际评分时,我拉出具有 totalUsersCount 作为属性的帖子,我提取所有用户的实际评分,将它们加在一起,然后将两个数字输入算法以吐出实际评分。我在客户端上完成所有这些。我怎样才能使用类似于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)
})
})
这不是关于 algoToComputeStarRating 的问题,我可以在客户端上进行。我想使用云函数将所有用户的评分加在一起,然后将该结果作为属性添加到帖子中。这样,当我拉出帖子时,我所要做的就是:
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)
})
数据库结构:
@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
这是我迄今为止尝试过的:
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);
});
}
});
});
【问题讨论】:
-
这种情况太常见了,firebase 文档甚至有一本手册:firebase.google.com/docs/firestore/solutions/counters
-
我不是原生 Javascript/Node 开发人员。如果这是 Swift,我可以轻而易举地解决这个问题,但我必须做大量研究才能在 Javascript 中解决这个问题,这就是我问这个问题的原因。
标签: ios swift firebase-realtime-database google-cloud-functions