如何使用 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 不更新