有没有一种方法可以对多个子集合流进行分组和映射?

时间:2020-03-23 10:33:42

标签: flutter dart google-cloud-firestore

我在Firestore中有一个用户集合,其中有2个子集合,分别是私有的和公共的。我想在Stream中获取用户模型。因此,我获得了用户文档的快照并将其映射到用户模型。但是,当我拥有这两个子集合时,该如何工作?因为这两个子集合都需要自己的流,对吗?如何将其组合成一个用户模型?到目前为止,这就是我的问题,当我试图从快照中获取用户模型中的私有和公共子集合时,我的问题就开始了,并且意识到它们都是自己的流。我也想将任何异步的东西都排除在我的用户模型之外。我现在认为我需要以某种方式创建将两个子集合文档都映射到单个模型的流,但是我该怎么做?

UserModel

    import 'package:cloud_firestore/cloud_firestore.dart';
    import 'package:flutter/foundation.dart';

    class UserModel {

      final String id;
      final String phoneNumber;
      final String name;

      UserModel._internal({
        @required this.id,
        @required this.phoneNumber,
        @required this.name,
      })  : assert(id != null),
      assert(phoneNumber != null),
      assert(name != null);

      factory UserModel.fromFirebase(DocumentSnapshot snapshot)
      {
        return UserModel._internal(
          id: snapshot.documentID ?? '',
//snapshot is a stream so this will be async which is not nice. Should I map both public and private into one usermodel somehow?
          phoneNumber: snapshot.reference.collection('public').document('data'). ?? '',
//snapshot is a stream so this will be async which is not nice. Should I map both public and private into one usermodel somehow?
          name: snapshot.reference.collection('public').document('data').  ?? '',
        );
      }

    }

UserProvider

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:app_name/data/models/user_authentication_certificate.dart';
import 'package:app_name/data/models/user_model.dart';

class UserProvider {
  static const userCollectionKey = 'users';
  final CollectionReference userCollection =
      Firestore.instance.collection(userCollectionKey);

  Stream<UserModel> me(UserAuthenticationCertificate certificate) {
    return userCollection.document(certificate.userID).snapshots().map((snapshot) =>
        UserModel.fromFirebase(snapshot));
  }
}

修改

我以为我通过压缩流解决了这个问题。但事实证明,它似乎仅在每个流都已更改时才发出。有什么解决办法吗?

  Stream<UserModel> me(UserAuthenticationCertificate certificate) {
    Stream<DocumentSnapshot> userData = userCollection.document(certificate.userID).snapshots();
    Stream<DocumentSnapshot> privateUserData = userCollection.document(certificate.userID).collection('private').document('data').snapshots();
    Stream<DocumentSnapshot> publicUserData = userCollection.document(certificate.userID).collection('public').document('data').snapshots();
    return StreamZip([userData, privateUserData, publicUserData]).asBroadcastStream().map((snapshot) => UserModel.fromFirebase(snapshot));
  }

2 个答案:

答案 0 :(得分:1)

我最终使用rxdart来使用CombineLatestStream,它确实满足了我的需要!

import 'package:rxdart/rxdart.dart';
import 'dart:async';

  Stream<UserModel> me(UserAuthenticationCertificate certificate) {
    Stream<DocumentSnapshot> userData = userCollection.document(certificate.userID).snapshots();
    Stream<DocumentSnapshot> privateUserData = userCollection.document(certificate.userID).collection('private').document('data').snapshots();
    Stream<DocumentSnapshot> publicUserData = userCollection.document(certificate.userID).collection('public').document('data').snapshots();
    return CombineLatestStream([userData, privateUserData, publicUserData], (values) => values.toList()).asBroadcastStream().map((snapshot) => UserModel.fromFirebase(snapshot));
  }

答案 1 :(得分:1)

您可以使用RxDart中的MergeStream合并两个流 这是文档链接

https://pub.dev/documentation/rxdart/latest/rx/MergeStream-class.html

和这里的另一个链接以了解其工作原理

https://rxmarbles.com/#merge