如何将Flutter中两个Firestore集合中的数据合并在一起? [英] How do I join data from two Firestore collections in Flutter?

查看:107
本文介绍了如何将Flutter中两个Firestore集合中的数据合并在一起?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Flutter中,我有一个使用Firestore的聊天应用程序,并且有两个主要集合:

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

  • chats,在自动ID上键入,具有messagetimestampuid字段.
  • users,键在uid上,并且具有name字段
  • chats, which is keyed on auto-ids, and has message, timestamp, and uid fields.
  • users, which is keyed on uid, and has a name field

在我的应用中,我使用以下小部件显示消息列表(来自messages集合):

In my app I show a list of messages (from the messages collection), with this widget:

class ChatList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var messagesSnapshot = Firestore.instance.collection("chat").orderBy("timestamp", descending: true).snapshots();
    var streamBuilder = StreamBuilder<QuerySnapshot>(
          stream: messagesSnapshot,
          builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> querySnapshot) {
            if (querySnapshot.hasError)
              return new Text('Error: ${querySnapshot.error}');
            switch (querySnapshot.connectionState) {
              case ConnectionState.waiting: return new Text("Loading...");
              default:
                return new ListView(
                  children: querySnapshot.data.documents.map((DocumentSnapshot doc) {
                    return new ListTile(
                      title: new Text(doc['message']),
                      subtitle: new Text(DateTime.fromMillisecondsSinceEpoch(doc['timestamp']).toString()),
                    );
                  }).toList()
                );
            }
          }
        );
        return streamBuilder;
  }
}

但是现在我想显示每条消息的用户名(来自users集合).

But now I want to show the user's name (from the users collection) for each message.

我通常称其为客户端联接,尽管我不确定Flutter是否为其指定名称.

I normally call that a client-side join, although I'm not sure if Flutter has a specific name for it.

我找到了一种执行此操作的方法(我在下面发布了此方法),但想知道在Flutter中是否有另一种/更好/更惯用的方法来进行此类操作.

I've found one way to do this (which I've posted below), but wonder if there is another/better/more idiomatic way to do this type of operation in Flutter.

所以:在Flutter中,惯用的方式是如何在上述结构中查找每条消息的用户名?

So: what is the idiomatic way in Flutter to look up the user name for each message in the above structure?

推荐答案

您可以像这样使用RxDart来做到这一点. https://pub.dev/packages/rxdart

You can do it with RxDart like that.. https://pub.dev/packages/rxdart

import 'package:rxdart/rxdart.dart';

class Messages {
  final String messages;
  final DateTime timestamp;
  final String uid;
  final DocumentReference reference;

  Messages.fromMap(Map<String, dynamic> map, {this.reference})
      : messages = map['messages'],
        timestamp = (map['timestamp'] as Timestamp)?.toDate(),
        uid = map['uid'];

  Messages.fromSnapshot(DocumentSnapshot snapshot)
      : this.fromMap(snapshot.data, reference: snapshot.reference);

  @override
  String toString() {
    return 'Messages{messages: $messages, timestamp: $timestamp, uid: $uid, reference: $reference}';
  }
}

class Users {
  final String name;
  final DocumentReference reference;

  Users.fromMap(Map<String, dynamic> map, {this.reference})
      : name = map['name'];

  Users.fromSnapshot(DocumentSnapshot snapshot)
      : this.fromMap(snapshot.data, reference: snapshot.reference);

  @override
  String toString() {
    return 'Users{name: $name, reference: $reference}';
  }
}

class CombineStream {
  final Messages messages;
  final Users users;

  CombineStream(this.messages, this.users);
}

Stream<List<CombineStream>> _combineStream;

@override
  void initState() {
    super.initState();
    _combineStream = Observable(Firestore.instance
        .collection('chat')
        .orderBy("timestamp", descending: true)
        .snapshots())
        .map((convert) {
      return convert.documents.map((f) {

        Stream<Messages> messages = Observable.just(f)
            .map<Messages>((document) => Messages.fromSnapshot(document));

        Stream<Users> user = Firestore.instance
            .collection("users")
            .document(f.data['uid'])
            .snapshots()
            .map<Users>((document) => Users.fromSnapshot(document));

        return Observable.combineLatest2(
            messages, user, (messages, user) => CombineStream(messages, user));
      });
    }).switchMap((observables) {
      return observables.length > 0
          ? Observable.combineLatestList(observables)
          : Observable.just([]);
    })
}

对于rxdart 0.23.x

for rxdart 0.23.x

@override
      void initState() {
        super.initState();
        _combineStream = Firestore.instance
            .collection('chat')
            .orderBy("timestamp", descending: true)
            .snapshots()
            .map((convert) {
          return convert.documents.map((f) {

            Stream<Messages> messages = Stream.value(f)
                .map<Messages>((document) => Messages.fromSnapshot(document));

            Stream<Users> user = Firestore.instance
                .collection("users")
                .document(f.data['uid'])
                .snapshots()
                .map<Users>((document) => Users.fromSnapshot(document));

            return Rx.combineLatest2(
                messages, user, (messages, user) => CombineStream(messages, user));
          });
        }).switchMap((observables) {
          return observables.length > 0
              ? Rx.combineLatestList(observables)
              : Stream.value([]);
        })
    }

这篇关于如何将Flutter中两个Firestore集合中的数据合并在一起?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆