Flutter异步函数更新Firestore文档后未同步使用更新数据问题
问题与解决方案
问题描述
我编写了一个Flutter异步函数joinUserToChallenge,逻辑为先更新ChallengesRecord文档将当前用户加入挑战,再基于更新后的文档数据批量更新ff_user_push_notifications集合中的文档用于推送通知。但实际运行时,批量更新操作并未使用更新后的ChallengesRecord数据,而是调用了更新前的旧数据。控制台输出显示文档更新已成功完成,但修改代码后问题依旧。
原代码
Future<void> joinUserToChallenge(ChallengesRecord challenge) async { //this updates the ChallengesRecord challenge final challengesUpdateData = { 'users_inchallenge': FieldValue.arrayUnion([currentUserReference]) }; await challenge.reference.update(challengesUpdateData).then((value) => print('success')); //this then queries the notification documents to be updated then //iterates through them to update each one on a batch.commit() //however it is not using the updated challenges doc it appears final batch = FirebaseFirestore.instance.batch(); await FirebaseFirestore.instance .collection('ff_user_push_notifications') .where(filter 1) .where(filter 2) .get().then((snapshots) => { snapshots.docs.forEach((doc) => { batch.update(doc.reference, { "user_refs" : challenge .usersInchallenge.map((u) => u.path).join(',') }), print(snapshots.docs.length) }) }); await batch.commit(); }
更新后的尝试代码
Future<void> joinUserToChallenge(ChallengesRecord challenge) async { //this updates the ChallengesRecord challenge final challengesUpdateData = { 'users_inchallenge': FieldValue.arrayUnion([currentUserReference]) }; await challenge.reference.update(challengesUpdateData).then((value) => print('success')); final batch = FirebaseFirestore.instance.batch(); await FirebaseFirestore.instance .collection('ff_user_push_notifications') .where(filter 1) .where(filter 2) .get(); pushNotificiations.docs.forEach((doc) => { batch.update(doc.reference, { "user_refs" : challenge .usersInchallenge.map((u) => u.path).join(',') }), }); await batch.commit() }
问题原因与解决办法
核心原因
你手中的challenge对象是更新前的本地实例,即便成功更新了Firestore云端的文档,这个本地对象的usersInchallenge属性不会自动同步更新,导致后续批量更新时依然使用旧数据。
解决方法
方法1:手动更新本地对象属性
在成功更新Firestore文档后,直接将当前用户添加到本地challenge对象的usersInchallenge列表中:
Future<void> joinUserToChallenge(ChallengesRecord challenge) async { final challengesUpdateData = { 'users_inchallenge': FieldValue.arrayUnion([currentUserReference]) }; await challenge.reference.update(challengesUpdateData); print('success'); // 手动更新本地对象的属性 challenge.usersInchallenge.add(currentUserReference); final batch = FirebaseFirestore.instance.batch(); final snapshots = await FirebaseFirestore.instance .collection('ff_user_push_notifications') .where(filter1) .where(filter2) .get(); snapshots.docs.forEach((doc) { batch.update(doc.reference, { "user_refs": challenge.usersInchallenge.map((u) => u.path).join(',') }); }); await batch.commit(); }
方法2:重新从Firestore拉取最新文档
更新完成后,重新获取该挑战文档的最新数据,替换本地的challenge对象:
Future<void> joinUserToChallenge(ChallengesRecord challenge) async { final challengesUpdateData = { 'users_inchallenge': FieldValue.arrayUnion([currentUserReference]) }; await challenge.reference.update(challengesUpdateData); print('success'); // 重新拉取最新的挑战文档数据 final updatedDoc = await challenge.reference.get(); final updatedChallenge = ChallengesRecord.fromSnapshot(updatedDoc); final batch = FirebaseFirestore.instance.batch(); final snapshots = await FirebaseFirestore.instance .collection('ff_user_push_notifications') .where(filter1) .where(filter2) .get(); snapshots.docs.forEach((doc) { batch.update(doc.reference, { "user_refs": updatedChallenge.usersInchallenge.map((u) => u.path).join(',') }); }); await batch.commit(); }
额外修复点
更新后的尝试代码中存在未定义变量pushNotificiations的问题,需要将get()的结果赋值给该变量,如上述解决代码中的写法。
内容的提问来源于stack exchange,提问作者Dennis Ashford
相关产品推荐
相关产品推荐

