Firebase模拟器中的单次更新后,Firestore文档被读取多次

qvtsj1bj  于 2022-12-04  发布在  其他
关注(0)|答案(1)|浏览(156)

我使用Firestore来保存用户数据。我的应用程序中的每个用户都有一个流来监听用户的文档。我正在运行Firestore模拟器,并注意到有时在用户文档更新后,文档被读了两次或更多次。我已经从Firestore模拟器中附加了一个图像来显示这一点。有什么原因可以解释为什么我在一次更新后得到了多次读取。我没有在流之外对用户文档进行任何读取。

我正在使用Flutter移动的应用程序来查看用户文档“.snapshots()"。此代码中的print语句只打印一次读取。但如果我只在流中阅读用户文档,那么我如何在模拟器中结束两次读取?

Stream<MyProfile?> watchMyProfile() {
    return _firestore
        .doc(PathService.user(uid))
        .withConverter<MyProfile>(
          fromFirestore: (snapshot, _) {
            return MyProfile.fromJson(snapshot.data()!);
          },
          toFirestore: (myProfile, _) => myProfile.toJson(),
        )
        .snapshots()
        .map((doc) => doc.data())
        .map(
      (myProfile) {
        // THIS ONLY PRINTS ONCE.
        debugPrint('watchMyProfile - read my profile');
        return myProfile;
      },
    );
  }

UPDATE 1:为了确保在firestore.rules文件中更新后没有阅读任何用户文档,我使用了如下代码:

allow update: if true;
allow get: if true;
allow list: if true;

不幸的是,在更新用户文档后,我仍然看到大量的读取。

nkhmeac6

nkhmeac61#

我已经在我这边重现了这个问题,发现了同样的行为。正如你在提供的图片中看到的,阅读量明显增加了。

这是由于在流中构造流。每次调用build()时都会重新创建流,如果页面上有动画,每秒最多可创建60次。
我建议您在一个私有变量中构造流,然后在流中使用它,这样它就不会在每个构建方法中被重新创建,并且只被调用一次。
像这样的东西

class SomeClass extends State<Some_State>{
    final Stream<MyProfile> _usersStream =             
    FirebaseFirestore.instance.collection('users').doc('ABC123').snapshots();
    
@override
  Widget build(BuildContext context) {
    return StreamBuilder<MyProfile>(
      stream: _usersStream,
        builder: (context, snapshot) {
        //…
  }
}

作为参考,文档的真实的更新由StreamBuilder完成,如此处所示

相关问题