Flutter объединяет два потока firestore в один поток

Я просто хочу выполнить операцию «ИЛИ» и получить оба результата двух запросов в один поток.

Вот мой код с одним потоком

 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, но он не работает, так как виджеты восстанавливаются.

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.

Я просто хочу получить оба результата двух запросов в один поток.


person Praneeth Dhanushka Fernando    schedule 13.11.2018    source источник
comment
Можете ли вы связать .where() звонки?   -  person Phix    schedule 13.11.2018
comment
Вы можете связать, и он станет оператором И, а не ИЛИ, вот в чем проблема .. Простое ИЛИ, где можно решить эту проблему, но такая опция недоступна   -  person Praneeth Dhanushka Fernando    schedule 14.11.2018
comment
@PraneethDhanushkaFernando Удалось ли вам обойти эту проблему?   -  person m-bhole    schedule 19.11.2018
comment
@hadooper нет, братан все еще борется   -  person Praneeth Dhanushka Fernando    schedule 20.11.2018
comment
У меня та же проблема в конце концов, что вы сделали, чтобы исправить проблему   -  person GILO    schedule 08.07.2019


Ответы (4)


Это должно сработать.

//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()
            );
          }
      ),
    );
  }

Надеюсь это поможет!!!

person m-bhole    schedule 20.11.2018
comment
@PraneethDhanushkaFernando, пожалуйста, попробуйте это и дайте мне знать, сработало ли это. Спасибо - person m-bhole; 20.11.2018
comment
StreamZip нельзя использовать для этого братана. Раньше он объединял потоки, которые принадлежат друг другу, например заголовок и сообщение. - person Praneeth Dhanushka Fernando; 22.11.2018
comment
в этом случае вам понадобится вложенный streambuilder - person m-bhole; 22.11.2018
comment
Это сработало в моем конкретном случае. Я занимался этим весь день, но все же наткнулся на твой ответ. Спасибо @ m-bhole, из будущего :) - person Chichebe; 08.11.2020
comment
не забудьте добавить асинхронность в свои зависимости - person lenz; 14.12.2020

Я не понимаю, почему вы используете forEach и Observable.just ().

Вы можете просто объединить два потока firestore напрямую, например:

Наблюдаемый.merge ([поток1, поток2]). Канал (объединить поток);

Wherre stream1 / 2 - это просто снимок вашего хранилища.

person Jason Scott    schedule 17.11.2018
comment
Откуда приходит combStream? - person Praneeth Dhanushka Fernando; 19.11.2018
comment
Просто создайте новый PublishSubject или StreamContoller для combStream. - person Jason Scott; 20.11.2018
comment
Я попробовал ваше предложение, но оно не удалось. Проблема, поскольку stream1 - это снимок запроса firestore, когда я пытался вызвать слияние, он говорит, что я пытаюсь объединить пустой поток. Это потому, что потоки stream1 и stream2 еще не инициализированы, поскольку они ожидают firestore. Как я могу убедиться, что потоки stream1 и sream2 инициализированы перед вызовом слияния? - person Praneeth Dhanushka Fernando; 20.11.2018

Что ж, я опаздываю, но просто выложу это здесь.

Вы можете добавить предложение whereIn в свой запрос следующим образом:

Firestore.instance.collection("collection_name").where("field",whereIn:["false","true"]).snapshots();
person Abhishek Kumar    schedule 17.05.2020
comment
Это вообще не работает! - person Hassan Ansari; 24.12.2020
comment
Возможно, они изменили методы. - person Abhishek Kumar; 18.05.2021

Я использовал пакет 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),
      ));
    });
person Vishal    schedule 22.12.2019
comment
Вы использовали CombineLatestStream...., тогда каков дальнейший код? Пожалуйста, поделитесь полным кодом, чтобы я и другие пользователи могли понять, что происходит? Это просто просьба :) Спасибо. - person Kamlesh; 18.06.2021