我有一个案例,一个用户想注册一个课程。
如果课程已满,则用户可在等候名单上登记。如果为此课程打开了一个空闲插槽,该用户将自动注册。为了实现等待列表自动化,我使用了一个带有.onUpdate触发器的云函数(CF),它可以工作。
CF示例:课程已满。参与者取消注册。CF启动并检查课程中是否有空位,以及等候名单上的用户是否尚未注册。如果是这样,则CF从课程中的等待列表中注册用户。
同时,在UI中,当一个插槽可用时,我允许已经在等候名单上的同一个用户注册该课程。通过注册课程,我把他从等候名单上除名。
对于这个实现,我使用了一个transaction,它只在用户尚未在课程中注册时才能完成。
由于某些原因,用户有时会注册两次。
我的问题是: onUpdate函数是否锁定文档?我是否需要在transaction函数中使用onUpdate来侦听同一文档的更改?对我来说,=>这样做是没有意义的。
处理这个错误的最简单的方法是让用户先从等候名单中注销,然后注册课程。不过,我想了解如何才能实现上述逻辑。
在颤振交易:
@override
Future<void> selfSetCourseParticipantWithStashedCreditPoint(
String courseEventId, Participant participantToAdd) async {
try {
UsedCreditPointInfo participantsCreditPoint =
participantToAdd.usedCreditPointInfo;
await _firestore.runTransaction((transaction) async {
// 1) Check if the customer does still have an available credit point left
final userRef = _usersCollection.doc(participantToAdd.uid);
var userDocumentSnapshot = await transaction.get(userRef);
var stashedCreditPoints =
userDocumentSnapshot.data()['${participantToAdd.creditPointPath}'];
var creditPointExists = false;
for (var usedCreditPointInfoMap in stashedCreditPoints) {
var usedCreditPoint =
UsedCreditPointInfo.fromMap(usedCreditPointInfoMap);
if (usedCreditPoint == participantsCreditPoint) {
creditPointExists = true;
break;
}
}
// if the credit point does not exist, then the transaction must fail
if (!creditPointExists) return null;
final courseRef = _courseEventsCollection.doc(courseEventId);
final courseEventDocumentSnapshot = await transaction.get(courseRef);
// 2) if the courseEvent document exists I have to check first if there are slots left
var currentCourseEvent = CourseEvent.fromEntity(
CourseEventEntity.fromSnapshot(courseEventDocumentSnapshot));
//todo: add the remaining requirements, e.g., registration date limit
if (currentCourseEvent.participants.length >=
currentCourseEvent.maxParticipants) {
return null;
}
if (currentCourseEvent.waitingList != null) {
var waitingList = currentCourseEvent.waitingList;
for (var i = 0; i < waitingList.length; i++) {
final waitingListParticipant = waitingList[i];
if (waitingListParticipant.uid == participantToAdd.uid) {
waitingList.removeAt(i);
break;
}
}
}
// add only if the participant is not already included to the list
if (!currentCourseEvent.participants.contains(participantToAdd)) {
currentCourseEvent = currentCourseEvent.copyWith(
participants: List.from(currentCourseEvent.participants)
..add(participantToAdd),
);
// the user document exists at this point, thus update is sufficient
transaction.update(
userRef,
{
'${participantToAdd.creditPointPath}': FieldValue.arrayRemove(
[participantToAdd.usedCreditPointInfo?.toMap()])
},
);
return transaction.set(
courseRef, currentCourseEvent.toEntity().toMap());
}
});
} catch (e, s) {
return handleFirestoreError(e, s);
}
}一段我的CF:
export const notifyOnCourseEventUpdateAndWaitingListRegistration = functions.firestore
.document("CourseEvents/{courseEvent}")
.onUpdate(async (change, context) => {
return firestore
.runTransaction(async (transaction) => {
const courseEventRef = firestore
.collection("CourseEvents")
.doc(change.after.data().firebaseId);
const courseEventSnapshot = await transaction.get(courseEventRef);
const courseEvent = courseEventSnapshot.data() as CourseEvent;
const currentCourseEvent = change.after.data() as CourseEvent;
const currentParticipants = currentCourseEvent.participants;
const previousCourseEvent = change.before.data() as CourseEvent;
const previousParticipants = previousCourseEvent.participants;
const currentMaxParticipants = currentCourseEvent.maxParticipants;
const currentWaitingList = currentCourseEvent.waitingList;
...
})
});发布于 2020-11-05 21:09:43
onUpdate函数是否锁定文档?
不是的。
,我是否需要onUpdate函数中的事务来侦听同一文档的更改?
我不太清楚这个问题在问什么,但无论如何,如果您希望更新两段并发运行的代码,以安全地更新同一个文档而不覆盖彼此,那么您就需要一个事务。
事务不“监听”文档中的更改。当检测到冲突时,它们只是通过重试事务处理程序函数来确保两个客户端在对同一个文档进行事务处理时不能相互覆盖。
https://stackoverflow.com/questions/64702630
复制相似问题