如何将Flutter中两个Firestore集合中的数据合并在一起? [英] How do I join data from two Firestore collections in Flutter?
问题描述
在Flutter中,我有一个使用Firestore的聊天应用程序,并且有两个主要集合:
I have a chat app in Flutter using Firestore, and I have two main collections:
-
chats
,在自动ID上键入,具有message
,timestamp
和uid
字段. -
users
,键在uid
上,并且具有name
字段
chats
, which is keyed on auto-ids, and hasmessage
,timestamp
, anduid
fields.users
, which is keyed onuid
, and has aname
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屋!