How do I join data from two Firestore collections in Flutter?

前端 未结 6 871
名媛妹妹
名媛妹妹 2020-11-29 02:27

I have a chat app in Flutter using Firestore, and I have two main collections:

  • chats, which is keyed on auto-ids, and has message,
6条回答
  •  情话喂你
    2020-11-29 03:04

    The first solution I got working is to nest two StreamBuilder instances, one for each collection/query.

    class ChatList extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        var messagesSnapshot = Firestore.instance.collection("chat").orderBy("timestamp", descending: true).snapshots();
        var usersSnapshot = Firestore.instance.collection("users").snapshots();
        var streamBuilder = StreamBuilder(
          stream: messagesSnapshot,
          builder: (BuildContext context, AsyncSnapshot messagesSnapshot) {
            return StreamBuilder(
              stream: usersSnapshot,
              builder: (context, usersSnapshot) {
                if (messagesSnapshot.hasError || usersSnapshot.hasError || !usersSnapshot.hasData)
                  return new Text('Error: ${messagesSnapshot.error}, ${usersSnapshot.error}');
                switch (messagesSnapshot.connectionState) {
                  case ConnectionState.waiting: return new Text("Loading...");
                  default:
                    return new ListView(
                      children: messagesSnapshot.data.documents.map((DocumentSnapshot doc) {
                        var user = "";
                        if (doc['uid'] != null && usersSnapshot.data != null) {
                          user = doc['uid'];
                          print('Looking for user $user');
                          user = usersSnapshot.data.documents.firstWhere((userDoc) => userDoc.documentID == user).data["name"];
                        }
                        return new ListTile(
                          title: new Text(doc['message']),
                          subtitle: new Text(DateTime.fromMillisecondsSinceEpoch(doc['timestamp']).toString()
                                              +"\n"+user),
                        );
                      }).toList()
                    );
                }
            });
          }
        );
        return streamBuilder;
      }
    }
    

    As stated in my question, I know this solution is not great, but at least it works.

    Some problems I see with this:

    • It loads all users, instead of just the users who posted messages. In small data sets that won't be a problem, but as I get more messages/users (and use a query to show a subset of them) I'll be loading more and more users who didn't post any messages.
    • The code is not really very readable with the nesting of two builders. I doubt this is idiomatic Flutter.

    If you know a better solution, please post as an answer.

提交回复
热议问题