首页 文章

如何在streambuilder中查询firestore文档并更新listview

提问于
浏览
1

我正在尝试从名为"posts"的Firestore集合中检索帖子,其中包含 post creator's userID 和帖子说明,这可以通过使用StreamBuilder和FutureBuilder实现(不可取,因为它只获取一次快照,并且在字段时不会更新变化) .

但是,我想使用 post creator's userID 查询另一个名为"users"的集合,并检索与userId匹配的文档 .

这是我的第一个方法:

StreamBuilder<QuerySnapshot>(
  stream:Firestore.instance.collection("posts").snapshots(),
  builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
    if (!snapshot.hasData) {
      return Center(
        child: _showProgressBar,
      );
    }

   List<DocumentSnapshot> reversedDocuments = snapshot.data.documents.reversed.toList();
    return ListView.builder(
      itemCount: reversedDocuments.length,
      itemBuilder: (BuildContext context, int index){

        String postAuthorID = reversedDocuments[index].data["postAuthorID"].toString();
        String postAuthorName = '';
        Firestore.instance.collection("users")
        .where("userID", isEqualTo: postAuthorID).snapshots().listen((dataSnapshot) {
            print(postAuthorName = dataSnapshot.documents[0].data["username"]);
          setState(() {
            postAuthorName = dataSnapshot.documents[0].data["username"];                  
          });
        });

        String desc = reversedDocuments[index].data["post_desc"].toString();

        return new ListTile(
          title: Container(
            child: Row(
              children: <Widget>[
                Expanded(
                  child: Card(
                    child: new Column(
                      children: <Widget>[
                        ListTile(
                          title: Text(postAuthorName, //Here, the value is not changed, it holds empty space.
                            style: TextStyle(
                              fontSize: 20.0,
                            ),
                          ),
                          subtitle: Text(desc),
                        ),
                       )

在了解ListView.builder()只能基于DocumentSnapshot列表呈现项目并且无法处理构建器内的查询之后 .

After many research: 我尝试了许多替代方案,尝试在initState()中构建列表,尝试使用嵌套流构建器:

return StreamBuilder<QuerySnapshot>(
  stream: Firestore.instance.collection('posts').snapshots(),
  builder: (context, snapshot1){
    return StreamBuilder<QuerySnapshot>(
      stream: Firestore.instance.collection("users").snapshots(),
      builder: (context, snapshot2){
        return ListView.builder(
          itemCount: snapshot1.data.documents.length,
          itemBuilder: (context, index){
            String desc = snapshot1.data.documents[index].data['post_description'].toString();
            String taskAuthorID = snapshot1.data.documents[index].data['post_authorID'].toString();
            var usersMap = snapshot2.data.documents.asMap();
            String authorName;
            username.forEach((len, snap){
              print("Position: $len, Data: ${snap.data["username"]}");
              if(snap.documentID == post_AuthorID){
                authorName = snap.data["username"].toString();
              }
            });
            return ListTile(
              title: Text(desc),
              subtitle: Text(authorName), //Crashes here...
            );
          },
        );
      }
    );
  }
);

尝试使用Stream Group并且无法找到完成此操作的方法,因为它只组合了两个流,但我希望第二个流可以从第一个流中获取值 .

这是我的Firebase Collection截图:

Firestore "posts" collection:
Firestore "posts" Collection

Firestore "users"系列:
Firestore "users" collection

我知道这是一件非常简单的事情,但仍然找不到任何教程或文章来实现这一点 .

2 回答

  • -1

    我发布了一个类似的问题,后来找到了一个解决方案:让itemBuilder返回状态的小部件并在其中使用FutureBuilder .

    Additional query for every DocumentSnapshot within StreamBuilder

    这是我的代码 . 在您的情况下,您可能希望使用新的Stateful小部件而不是ListTile,因此您可以添加FutureBuilder来调用异步函数 .

    StreamBuilder(
                      stream: Firestore.instance
                          .collection("messages").snapshots(),
                      builder: (context, snapshot) {
                        switch (snapshot.connectionState) {
                          case ConnectionState.none:
                          case ConnectionState.waiting:
                            return Center(
                              child: PlatformProgressIndicator(),
                            );
                          default:
                            return ListView.builder(
                              reverse: true,
                              itemCount: snapshot.data.documents.length,
                              itemBuilder: (context, index) {
                                List rev = snapshot.data.documents.reversed.toList();
                                ChatMessageModel message = ChatMessageModel.fromSnapshot(rev[index]);
                                return ChatMessage(message);
                              },
                            );
                        }
                      },
                    )
    
    
    class ChatMessage extends StatefulWidget {
      final ChatMessageModel _message;
      ChatMessage(this._message);
      @override
      _ChatMessageState createState() => _ChatMessageState(_message);
    }
    
    class _ChatMessageState extends State<ChatMessage> {
      final ChatMessageModel _message;
    
      _ChatMessageState(this._message);
    
      Future<ChatMessageModel> _load() async {
        await _message.loadUser();
        return _message;
      }
    
      @override
      Widget build(BuildContext context) {
    
        return Container(
          margin: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 10.0),
          child: FutureBuilder(
            future: _load(),
            builder: (context, AsyncSnapshot<ChatMessageModel>message) {
              if (!message.hasData)
                return Container();
              return Row(
                children: <Widget>[
                  Container(
                    margin: const EdgeInsets.only(right: 16.0),
                    child: GestureDetector(
                      child: CircleAvatar(
                        backgroundImage: NetworkImage(message.data.user.pictureUrl),
                      ),
                      onTap: () {
                        Navigator.of(context)
                            .push(MaterialPageRoute(builder: (context) => 
                            ProfileScreen(message.data.user)));
                      },
                    ),
                  ),
                  Expanded(
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: <Widget>[
                        Text(
                          message.data.user.name,
                          style: Theme.of(context).textTheme.subhead,
                        ),
                        Container(
                            margin: const EdgeInsets.only(top: 5.0),
                            child: _message.mediaUrl != null
                                ? Image.network(_message.mediaUrl, width: 250.0)
                                : Text(_message.text))
                      ],
                    ),
                  )
                ],
              );
            },
          ),
        );
      }
    }
    class ChatMessageModel {
      String id;
      String userId;
      String text;
      String mediaUrl;
      int createdAt;
      String replyId;
      UserModel user;
    
      ChatMessageModel({String text, String mediaUrl, String userId}) {
        this.text = text;
        this.mediaUrl = mediaUrl;
        this.userId = userId;
      }
    
      ChatMessageModel.fromSnapshot(DocumentSnapshot snapshot) {
        this.id = snapshot.documentID;
        this.text = snapshot.data["text"];
        this.mediaUrl = snapshot.data["mediaUrl"];
        this.createdAt = snapshot.data["createdAt"];
        this.replyId = snapshot.data["replyId"];
        this.userId = snapshot.data["userId"];
      }
    
      Map toMap() {
        Map<String, dynamic> map = {
          "text": this.text,
          "mediaUrl": this.mediaUrl,
          "userId": this.userId,
          "createdAt": this.createdAt
        };
        return map;
    
      }
    
      Future<void> loadUser() async {
        DocumentSnapshot ds = await Firestore.instance
            .collection("users").document(this.userId).get();
        if (ds != null)
          this.user = UserModel.fromSnapshot(ds);
      }
    
    }
    
  • 0

    我也有这个问题,我正在尝试查询其子集合中的字段等于userid的特定文档

相关问题