首页 > 解决方案 > Flutter StreamBuilder 用于多个 firebase 文档

问题描述

usersCollection.document(user.uid)当对firebase 文档进行更改时,我正在尝试更新我的 Flutter 应用程序。

当用户文档更新时,我想从这个文档中检索数据,也从另一个 firebase 文档中检索数据,facilitiesCollection.document(...).

我当前的代码

Future<Map> _getCheckedInFacilityData() async {
  Map<String, dynamic> result = {};

  try {
    DocumentSnapshot userDoc =
        await _db.usersCollection.document(user.uid).get();

    if (userDoc.data['checkedIn']) {
      // User is checked in
      DocumentSnapshot facDoc = await _db.facilitiesCollection
          .document(userDoc.data['activeFacilityID'].toString())
          .get();

      result['facilityID'] = userDoc.data['activeFacilityID'];
      result['sessionID'] = userDoc.data['activeSessionID'];
      result['facilityActiveUsers'] = facDoc.data['activeUsers'].length;
      result['facilityName'] = facDoc.data['name'];

      return result;
    }
  } catch (er) {
    debugPrint(er.toString());
  }
  return null;
}
FutureBuilder<Map>(
  future: _getCheckedInFacilityData(),
  builder: (context, map) {
    switch (map.connectionState) {
      case ConnectionState.waiting:
        return Center(child: CircularProgressIndicator());
...

这目前正在运行,但是当对用户文档进行更改时,页面不会更新。我很久没有使用 Flutter/Dart,所以欢迎任何想法。

是否可以返回一个自定义对象/地图,该对象/地图由 2 个单独的文档组成StreamBuilder,或者是否有另一种方法适用于我的情况。

标签: firebaseflutterdart

解决方案


当然,您可以使用 Streams asyncMap() 来完成,然后在 StreamBuilder 中收听

基本算法

获取第一个数据类型的流,然后获取 asyncMap 以等待第二个数据类型并将它们都返回

stream.asyncMap(
  (v1) async {
    final v2 = await Future.delayed(Duration(seconds: 1), () => 4);
    return v1 * v2;
  },
);

更接近您的代码

Stream<Map<String, dynamic>> _getCheckedInFacilityData() {

  return _db.usersCollection.document(user.uid).snapshots()
      .asyncMap(
    (userDoc) async {
      final DocumentSnapshot facDoc =
          await _db.facilitiesCollection
      .document(userDoc.data['activeFacilityID'].toString())
      .get();
      final Map<String, dynamic> userMap = userDoc.data;
      final Map<String, dynamic> facMap = facDoc.data;
      return userMap..addAll(facMap);
    },
  );
}

在这个函数中,我合并了两个映射 - 如果两个映射具有相同的键映射将只保留最后一个在我们的例子中添加的键addAll(facMap)

最后一步是在屏幕上显示流数据 - 使用StreamBuilder

StreamBuilder<Map>(
  stream: _getCheckedInFacilityData(),
    builder: (context, snapshot) {
          if (snapshot.hasError) {
            return Text('${snapshot.error}');
          } else if (snapshot.connectionState == ConnectionState.waiting) {
            return LinearProgressIndicator();
          }
          
          return /* some widget that shows your data*/;
        },
      ),

推荐阅读