返回批量提交的Cloud函数不会等待该提交在完成之前对数据库进行更改



在Cloud Functions中,我定义了一个函数,该函数使用我提交的批进行some更新。此提交是函数的返回。这个函数只计算每个帖子的点赞数(在我的Firestore数据库中,点赞和帖子是两个不同的集合(。由于整个代码很短,而且很容易理解,所以我在下面展示它。

点赞或不点赞帖子(从点赞集合中添加或删除点赞文档(是由应用程序在客户端完成的。计算一些统计数据(例如,每个帖子的点赞数(的事实在下面的Cloud Function中位于服务器端。(因为如果是客户端,它将是可破解的,即会生成和保存错误的统计数据+处理统计数据与Android应用程序无关,因此它肯定应该在服务器端计算(。

需要注意的重要事项是:return batch.commit是此Cloud函数的返回

exports.sortPostsByUsersPostsLikes = functions.https.onCall((data, context) => {
if(!context.auth) {
throw new functions.https.HttpsError('failed-precondition', 'The function must be called while authenticated.');
}
const batch = admin.firestore().batch();
const posts = admin_firestore.collection('list_of_users_posts');
const likes = admin_firestore.collection('likes_of_users_posts');
const map_posts_id_with_number_of_likes = [];
likes.get().then(function(likes_docs) {
likes_docs.forEach(like_doc => {
if(!(like_doc.data().post in map_posts_id_with_number_of_likes)) {
map_posts_id_with_number_of_likes[like_doc.data().post] = 0;
}
map_posts_id_with_number_of_likes[like_doc.data().post] += 1;
});       
return posts.get();
}).then(function(posts_docs) {
posts_docs.forEach(post_doc => {
if(post_doc.id in map_posts_id_with_number_of_likes) {
batch.update(post_doc.ref, "number_of_likes", map_posts_id_with_number_of_likes[post_doc.id]);
} else {
batch.update(post_doc.ref, "number_of_likes", 0);
}
});     
return batch.commit();
}).catch(function(error) {
console.log("UNABLE TO SORT THE POSTS");
console.log(error);
throw new functions.https.HttpsError('unknown', 'An error occurred when trying to sort the posts.');
});
});

在我的Android应用程序中,当用户在帖子列表中喜欢帖子时:

  1. 首先,我在点赞集合中添加一个点赞
  2. 当赞成功添加到数据库中的赞集合中时,我会刷新帖子列表
  3. 当帖子列表显示(或刷新(时,我调用上面的云函数来重新计算帖子的点赞数(很快,"显示的帖子"(
  4. 当成功重新计算帖子的点赞数时,我会显示帖子(因此每个显示帖子的点赞数都是正确的(

问题

问题是:在第4步,每个帖子的点赞数都不正确(有时是,有时不是(。就好像云函数没有等待批处理提交结束一样。这是正常行为吗?是否有任何方法可以强制云函数等待批处理的提交成功?

我在Android应用程序中使用的代码是:

FirebaseFunctions.getInstance()
.getHttpsCallable("sortPostsByUsersPostsLikes")
.call()
.continueWith(new Continuation<HttpsCallableResult, Void>() {
@Override
public Void then(@NonNull final Task<HttpsCallableResult> task) {
if(requireActivity().isDestroyed() || requireActivity().isFinishing()) {
return null;
}
if(!task.isSuccessful()) {
Exception e = task.getException();
if (e instanceof FirebaseFunctionsException) {
FirebaseFunctionsException ffe = (FirebaseFunctionsException) e;
if(ffe.getCode() == FirebaseFunctionsException.Code.UNKNOWN) {
miscellaneous.showErrorPopIn(requireActivity(), R.string.error_sortPostsByUsersPostsLikes);
}
}
return null;
}
postsDatabaseModel.getListOfPostsOfUser(the_posts_owner).get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {

返回批提交并添加then不起作用

我尝试了以下方法,但不起作用:

.then(function(posts_docs) {
posts_docs.forEach(post_doc => {
if(post_doc.id in map_posts_id_with_number_of_likes) {
batch.update(post_doc.ref, "number_of_likes", map_posts_id_with_number_of_likes[post_doc.id]);
} else {
batch.update(post_doc.ref, "number_of_likes", 0);
}
});     
return batch.commit();
}).then(function() {
return true;
}).catch(function(error) {

您正确地链接了异步方法返回的promise,但您没有返回整个链。你应该做如下:

exports.sortPostsByUsersPostsLikes = functions.https.onCall((data, context) => {
if(!context.auth) {
throw new functions.https.HttpsError('failed-precondition', 'The function must be called while authenticated.');
}
const batch = admin.firestore().batch();
const posts = admin_firestore.collection('list_of_users_posts');
const likes = admin_firestore.collection('likes_of_users_posts');
const map_posts_id_with_number_of_likes = [];

// SEE THE ADDITION OF RETURN BELOW
return likes.get().then(function(likes_docs) {
likes_docs.forEach(like_doc => {
if(!(like_doc.data().post in map_posts_id_with_number_of_likes)) {
map_posts_id_with_number_of_likes[like_doc.data().post] = 0;
}
map_posts_id_with_number_of_likes[like_doc.data().post] += 1;
});       
return posts.get();
}).then(function(posts_docs) {
posts_docs.forEach(post_doc => {
if(post_doc.id in map_posts_id_with_number_of_likes) {
batch.update(post_doc.ref, "number_of_likes", map_posts_id_with_number_of_likes[post_doc.id]);
} else {
batch.update(post_doc.ref, "number_of_likes", 0);
}
});     
return batch.commit();
}).catch(function(error) {
console.log("UNABLE TO SORT THE POSTS");
console.log(error);
throw new functions.https.HttpsError('unknown', 'An error occurred when trying to sort the posts.');
});
});

我建议您观看关于";JavaScript承诺";来自Firebase系列视频(https://firebase.google.com/docs/functions/video-series/)强调了返回承诺的重要性。否则,在所有异步操作完成之前,云功能可能随时终止。


评论后更新

如果你想记录云功能成功的事实,你可以这样做:

exports.sortPostsByUsersPostsLikes = functions.https.onCall((data, context) => {
if(!context.auth) {
throw new functions.https.HttpsError('failed-precondition', 'The function must be called while authenticated.');
}
//...
return likes.get().then(function(likes_docs) {
//...      
return posts.get();
}).then(function(posts_docs) {
//...          
return batch.commit();
}).then(function() {
console.log("SUCCESS")   
return null;
})
.catch(function(error) {
//...
});
});

相关内容

  • 没有找到相关文章

最新更新