В облачных функциях я определил функцию, которая делает некоторые обновления, используя пакет, который я фиксирую. Этот коммит является возвращением функции. Эта функция просто вычисляет количество лайков каждого поста (лайки и посты - это две разные коллекции в моей базе данных Firestore). Поскольку весь код является коротким и очень простым для понимания, я покажу его ниже.
Тот факт, что публикация нравится или не нравится (добавление или удаление документа из коллекции лайков) выполняется клиентом приложение. Факт вычисления некоторой статистики (например, количества лайков на пост) ниже серверной части в следующей облачной функции. (потому что, если бы он был на стороне клиента, он был бы взломан, то есть была бы сгенерирована и сохранена плохая статистика + работа со статистикой не имеет отношения к приложению Android напрямую и поэтому должна определенно вычисляться на стороне сервера).
Важно отметить: return batch.commit
- это возвращение этой функции облака.
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, когда пользователь, в списке постов лайков:
- Сначала я добавляю лайк в коллекцию лайков
- Когда лайк успешно добавлен в коллекцию лайков в базе данных, я refre sh список постов
- Когда список постов показывается (или обновляется), я вызываю вышеупомянутую облачную функцию, чтобы пересчитать количество лайков постов (скоро, "из показанных сообщений").
- Когда число лайков постов успешно пересчитано, я показываю посты (поэтому число лайков каждого показанного поста будет правильным).
Вопрос
Проблема в том, что на шаге 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) {