Flutter 将两个 Firestore 流合并为一个流
Posted
技术标签:
【中文标题】Flutter 将两个 Firestore 流合并为一个流【英文标题】:Flutter merge two firestore streams into a single stream 【发布时间】:2019-04-16 16:22:45 【问题描述】:我只是想执行一个“或”运算并将两个查询的两个结果放到一个流中。
这是我的单流代码
StreamBuilder(
stream: Firestore.instance
.collection('list')
.where('id', isEqualTo: 'false')
.orderBy('timestamp')
.snapshots(),
builder: (context, snapshot)
if (!snapshot.hasData)
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(
child: CircularProgressIndicator(),
)
],
);
if (snapshot.data.documents.length == 0)
return const Center(
child: Text(
"Not Available",
style: TextStyle(fontSize: 30.0, color: Colors.grey),
),
);
return ListView.builder(
padding: EdgeInsets.all(5.0),
key: Key(randomString(20)),
itemCount: snapshot.data.documents.length,
itemBuilder: (BuildContext context, int index)
return ListCard(snapshot.data.documents[index]);
,
);
),
现在我想将两个流提供给同一个流构建器,而不是单个流。
我尝试了 StreamGroup,但自从 Widgets 重建后它无法正常工作
StreamGroup.merge([streamOne, streamTwo]).asBroadcastStream();
我也尝试了以下方法
Stream<List<DocumentSnapshot>> searchResult()
List<Stream<List<DocumentSnapshot>>> streamList = [];
Firestore.instance
.collection('room-list')
.where('id', isEqualTo: 'false')
.snapshots()
.forEach((snap)
streamList.add(Observable.just(snap.documents));
);
Firestore.instance
.collection('room-list')
.where('id', isEqualTo: 'pending')
.snapshots()
.forEach((snap)
streamList.add(Observable.just(snap.documents));
);
var x = Observable.merge(streamList)
.scan<List<DocumentSnapshot>>((acc, curr, i)
return acc ?? <DocumentSnapshot>[]
..addAll(curr);
);
return x;
这里我得到了错误,应该至少有一个流要合并。这是因为 Observable.merge(streamList) 在项目添加到 streamList 之前被调用。
我只是想将两个查询的两个结果合并到一个流中。
【问题讨论】:
你能链接.where()
调用吗?
你可以链接,它会变成一个 AND 运算符而不是 OR 这就是问题所在。一个简单的 OR 在哪里可以解决这个问题,但这样的选项不可用
@PraneethDhanushkaFernando 你设法解决了这个问题吗?
@hadooper nope 兄弟仍在苦苦挣扎
我也遇到了同样的问题,你是怎么解决这个问题的
【参考方案1】:
这应该可行。
//Change your streams here
Stream<List<QuerySnapshot>> getData()
Stream stream1 = Firestore.instance.collection('list').where('id', isEqualTo: 'false').orderBy('timestamp').snapshots();
Stream stream2 = Firestore.instance.collection('list').where('id', isEqualTo: 'true').orderBy('timestamp').snapshots();
return StreamZip([stream1, stream2]);
@override
Widget build(BuildContext context)
return new Scaffold(
body: StreamBuilder(
stream: getData(),
builder: (BuildContext context, AsyncSnapshot<List<QuerySnapshot>> snapshot1)
List<QuerySnapshot> querySnapshotData = snapshot1.data.toList();
//copy document snapshots from second stream to first so querySnapshotData[0].documents will have all documents from both query snapshots
querySnapshotData[0].documents.addAll(querySnapshotData[1].documents);
if (querySnapshotData[0].documents.isEmpty)
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(
child: CircularProgressIndicator(),
)
],
);
if (querySnapshotData[0].documents.length == 0)
return const Center(
child: Text(
"Not Available",
style: TextStyle(fontSize: 30.0, color: Colors.grey),
),
);
return new ListView(
children: querySnapshotData[0].documents.map((DocumentSnapshot document)
// put your logic here. You will have access to document from both streams as "document" here
return new ListCard(document);
).toList()
);
),
);
希望对你有帮助!!!
【讨论】:
@PraneethDhanushkaFernando 请试试这个,让我知道它是否有效。谢谢 StreamZip 不能用于这个兄弟。它用于组合彼此所属的流,如标题和帖子 在这种情况下,您将需要嵌套的流构建器 这适用于我的特殊情况。我整天都在努力,但我还是偶然发现了你的答案。谢谢@m-bhole,来自未来 :) 确保将异步添加到您的依赖项中【参考方案2】:我不确定你为什么要使用 forEach 和 Observable.just()。
您可以直接合并两个 Firestore 流,例如:
Observable.merge([stream1, stream2]).pipe(combineStream);
stream1/2 只是您的 Firestore 快照。
【讨论】:
combinStream 是从哪里来的? 只需为 combineStream 创建一个新的 PublishSubject 或 StreamContoller。 我尝试了您的建议,但失败了。当我尝试调用 merge 时,stream1 是一个 firestore 查询快照,它表示我正在尝试合并一个空流。这是因为 stream1 和 stream2 在等待 firestore 时尚未初始化。如何确保在调用合并之前初始化 stream1 和 sream2?【参考方案3】:我使用 RxDart 包来组合两个流,如下所示
RxDart - CombineLatestStream
final Stream<DocumentSnapshot> user = Firestore.instance
.collection("users")
.document(firebaseUser.uid)
.snapshots();
final Stream<QuerySnapshot> cards =
Firestore.instance.collection("cards").snapshots();
CombineLatestStream.list([user, cards]).listen((data)
add(LoadedHomeEvent(
data.elementAt(0),
data.elementAt(1),
));
);
【讨论】:
你用过CombineLatestStream....
那么进一步的代码是什么?请分享完整的代码,以便其他用户和我可以了解发生了什么?它只是一个请求:) 谢谢。【参考方案4】:
好吧,我迟到了,但我会把它放在那里。
您可以像这样在查询中添加 whereIn 子句:
Firestore.instance.collection("collection_name").where("field",whereIn:["false","true"]).snapshots();
【讨论】:
这根本行不通! 他们可能改变了方法。以上是关于Flutter 将两个 Firestore 流合并为一个流的主要内容,如果未能解决你的问题,请参考以下文章
将用户 uid 传递给 Flutter 中的 Firestore 流查询