如何使用 Stream Builder 从多个 firebase 集合中获取数据

Posted

技术标签:

【中文标题】如何使用 Stream Builder 从多个 firebase 集合中获取数据【英文标题】:How to get data from multiple firebase collections using a Stream Builder 【发布时间】:2021-05-27 09:23:45 【问题描述】:

My flutter app

我在使用流构建器访问 firebase 中两个不同集合的数据时遇到问题。我有一个名为 ForumPage 的 StatefulWidget,上面有一张图片。 ForumPage 有一列有多个子级,其中一个是 MyStreamBuilder StatelessWidget。这是我用来连接到 firebase 的小部件。

MyStreamBuilder

import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:hotel_for_dogs/Posts/need_post.dart';
import 'package:hotel_for_dogs/Posts/sitter_post.dart';

class MyStreamBuilder extends StatelessWidget 
  final String _typeOfPost;
  final String _state;
  final String _city;
  MyStreamBuilder(this._typeOfPost, this._state, this._city);

  @override
  Widget build(BuildContext context) 
    Stream stream = FirebaseFirestore.instance.collection(_typeOfPost).where('state', isEqualTo: _state).where('city', isEqualTo: _city).snapshots();
    return SizedBox(
        height: 400,
        child: StreamBuilder<QuerySnapshot>(
          // needPosts
        stream: stream,
        builder: (context, snapshot) 
          if (snapshot.hasData && snapshot.data.size > 0) 
            final List<DocumentSnapshot> documents = snapshot.data.docs;
            if(_typeOfPost == "needPosts") 
              return ListView(
                  children: documents
                      .map((doc) => Card( child: NeedPost(
                      doc['title'],
                      doc['dogBreed'],
                      doc['dogNeeds'],
                      doc['amountOfTime'],
                      doc['amountPerHour'],
                      doc['pottyTrained'],
                      doc['animalFriendly'],
                      doc['date'],
                      doc['state'],
                      doc['city'],
                      doc['dogName'],
                      doc['email'],
                      doc['phone'],
                      doc['fullName'])
                  ))
                      .toList());
             else 
              return ListView(
                  children: documents
                      .map((doc) => Card( child: SitterPost(
                      doc['title'],
                      doc['amountPerHour'],
                      doc['date'],
                      doc['state'],
                      doc['city'],
                      doc['email'],
                      doc['phone'],
                      doc['fullName'],
                      doc['breedSize'],
                      doc['bio'],
                      doc['fencedBackYard'],
                      doc['otherAnimals'])
                  ))
                      .toList());
            
           else if (snapshot.hasError) 
            return Text("error");
           else if(!snapshot.hasData)
            return Center(
              child: CircularProgressIndicator(),
            );
           else 
            return Text("No Data");
          
            ));
  

当用户输入州和城市时,他们可以点击“我是保姆”按钮,然后点击搜索。需要保姆的人的帖子会出现(当然如果有数据的话)。当用户点击“需要保姆”按钮时,就会出现保姆的帖子。当点击搜索按钮时,处理选择显示哪种帖子。这是该代码和另一张图片的代码!

My flutter app with some data entered

 setState(() 
                      if (iAmSitterColor == Colors.black && stateController.text.isNotEmpty && cityController.text.isNotEmpty) 
                        typeOfPost = "needPosts";
                        state = stateController.text;
                        city = cityController.text;
                       else if (needASitterColor == Colors.black && stateController.text.isNotEmpty && cityController.text.isNotEmpty) 
                        typeOfPost = "sitterPosts";
                        state = stateController.text;
                        city = cityController.text;
                      
                    );

设置状态会触发 UI 重建,因此 MyStreamBuilder 将获得更新的信息。

MyStreamBuilder(typeOfPost, state, city)

您可能已经从上一张图片中注意到,此代码可以正常工作,并且确实可以从 Firestore 中正确获取数据。但是,如果我在两个按钮之间切换并点击搜索,会出现一个红色屏幕,然后会出现帖子。当我的终端发生这种情况时,我会收到此错误

The following StateError was thrown building StreamBuilder<QuerySnapshot>(dirty, state: _StreamBuilderBaseState<QuerySnapshot, AsyncSnapshot<QuerySnapshot>>#fdcd8):
Bad state: field does not exist within the DocumentSnapshotPlatform

我想知道有没有更好的方法来做到这一点?我也厌倦了将 MyStreamBuilder 更改为:

import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:hotel_for_dogs/Posts/need_post.dart';
import 'package:hotel_for_dogs/Posts/sitter_post.dart';

class MyStreamBuilder extends StatelessWidget 
  final String _typeOfPost;
  final String _state;
  final String _city;
  MyStreamBuilder(this._typeOfPost, this._state, this._city);

  @override
  Widget build(BuildContext context) 
    Stream stream1 = FirebaseFirestore.instance.collection("needPosts").where('state', isEqualTo: _state).where('city', isEqualTo: _city).snapshots();
    Stream stream2 = FirebaseFirestore.instance.collection("sitterPosts").where('state', isEqualTo: _state).where('city', isEqualTo: _city).snapshots();

    if (_typeOfPost == "needPosts")
      return SizedBox(
          height: 400,
          child: StreamBuilder<QuerySnapshot>(
            // needPosts
              stream: stream1,
              builder: (context, snapshot) 
                if (snapshot.hasData && snapshot.data.size > 0) 
                  final List<DocumentSnapshot> documents = snapshot.data.docs;
                  return ListView(
                      children: documents
                          .map((doc) => Card( child: NeedPost(
                          doc['title'],
                          doc['dogBreed'],
                          doc['dogNeeds'],
                          doc['amountOfTime'],
                          doc['amountPerHour'],
                          doc['pottyTrained'],
                          doc['animalFriendly'],
                          doc['date'],
                          doc['state'],
                          doc['city'],
                          doc['dogName'],
                          doc['email'],
                          doc['phone'],
                          doc['fullName'])
                      ))
                          .toList());
                 else if (snapshot.hasError) 
                  return Text("error");
                 else if(!snapshot.hasData)
                  return Center(
                    child: CircularProgressIndicator(),
                  );
                 else 
                  return Text("No Data");
                
              ));
     else 
      return SizedBox(
          height: 400,
          child: StreamBuilder<QuerySnapshot>(
            // needPosts
              stream: stream2,
              builder: (context, snapshot) 
                if (snapshot.hasData && snapshot.data.size > 0) 
                  final List<DocumentSnapshot> documents = snapshot.data.docs;
                  return ListView(
                      children: documents
                          .map((doc) => Card( child: SitterPost(
                          doc['title'],
                          doc['amountPerHour'],
                          doc['date'],
                          doc['state'],
                          doc['city'],
                          doc['email'],
                          doc['phone'],
                          doc['fullName'],
                          doc['breedSize'],
                          doc['bio'],
                          doc['fencedBackYard'],
                          doc['otherAnimals'])
                      ))
                          .toList());
                 else if (snapshot.hasError) 
                  return Text("error");
                 else if(!snapshot.hasData)
                  return Center(
                    child: CircularProgressIndicator(),
                  );
                 else 
                  return Text("No Data");
                
              ));
    
  

它给了我同样的错误。我应该使用未来的建设者吗?我只看到未来的构建器被用来访问集合中的特定文档数据。我需要的是集合中的所有文档数据。

【问题讨论】:

尝试将您的 doc['FIELD_NAME'] 更改为 doc.data()['FIELD_NAME'],这可能会使错误消失。让我知道这是否有效。 我被震撼了。我现在有一个没有错误的工作解决方案。谢谢你,先生。回答问题并将其标记为已回答。 答案已发布:) 【参考方案1】:

发生这种情况是因为您没有正确地从 firestore 获取数据以在地图上进行设置。

要删除该警告,您需要在地图设置期间将代码中的 doc[FIELD_NAME] 结构更改为 doc.data()[FIELD_NAME]

【讨论】:

@KyleLynch 这是answer your question吗?

以上是关于如何使用 Stream Builder 从多个 firebase 集合中获取数据的主要内容,如果未能解决你的问题,请参考以下文章

颤振开发。通过 Stream Builder 从 Firebase Storage 和 Firestore 获取数据

Stream Builder 在 Flutter 中的先前数据之上更新数据

为啥不在 Stream API 中使用 reduce 来合并多个映射?

Stream 内的 Flutter ListView.Builder 不更新

Flutter,是不是可以在没有小部件构建方法的情况下在功能中使用 Firestore Stream Builder?

C++Builder 出现 Corrupt Portfolio stream错误修正方法