【问题标题】:How can I make a stream of parent/child objects from firestore如何从 Firestore 制作父/子对象流
【发布时间】:2020-03-17 16:06:49
【问题描述】:

我有一个具有层次关系的 Firestore 数据库。 “父”文档具有子对象的集合(“子”)。我想要一连串家长的反对意见。因此,如果 Fire 存储中的父级发生更改,则流应该提供一个新的 Parent 对象,其中所有子级都已加载。

下面的代码是我想要实现的。问题出现在标记为“====> 问题”的行中,该行已插入代码中。

编译器说:返回类型 'List>' 不是匿名closure.dart(return_of_invalid_type_from_closure) 定义的'List'。

我不知道如何将此流转换为“映射”调用到异步调用以获取 List 而不是 Future

有人知道 Flutter/Dart 中分层 Firestore 数据的好示例吗?

import 'package:cloud_firestore/cloud_firestore.dart';

final parentsCollection = Firestore.instance.collection('parents');

Stream<List<Parent>> jots() {
  return parentsCollection.snapshots().map((snapshot) {

 //====================================================
        return snapshot.documents //  <===== Problem
 //====================================================
        .map((doc) async { 
          var parentEntity = await ParentEntity.fromSnapshot(doc);
          return Parent.fromEntity(parentEntity);
        }).toList();
  });
}

class Parent {
  final String id;
  final String data;
  final List<Child> children ;

  Parent(this.data, {
    String id, 
    List<Child> children
  })
      : this.id = id ?? '',
        this.children = children ?? List<Child>()
    ;

  static Parent fromEntity(ParentEntity entity) {
    var parent = Parent(
      entity.data,
      id: entity.id,
      children: entity.children.map((c)=>Child.fromEntity(c))
    );
    return parent;
  }
}

class Child {
  final String id;
  final String label;

  Child(this.label, {String id})
      : this.id = id ?? '';

  static Child fromEntity(ChildEntity entity) {
    var child = Child(
      entity.label,
      id: entity.id,
    );
    return child;
  }
}

class ParentEntity {
  final String id;
  final String data;
  final List<ChildEntity> children;

  ParentEntity( this.id, this.data, this.children );

  static Future<ParentEntity> fromSnapshot(DocumentSnapshot snapshot) async {
    var children = await _childrenFromSnapshot(snapshot);
    return ParentEntity( 
      snapshot.documentID, 
      snapshot.data['data'], 
      children
    );
  }

  static Future<List<ChildEntity>> _childrenFromSnapshot(
      DocumentSnapshot snapshot) async {
    var childCollection = snapshot.reference.collection("children");
    QuerySnapshot docs = await childCollection.getDocuments();
    return docs.documents.map((doc) {
      return ChildEntity( doc.documentID, doc.data["label"]);
    });
  }
}

class ChildEntity {
  final String id;
  final String label;

  ChildEntity( this.id, this.label );

  static ChildEntity fromSnapshot(DocumentSnapshot snapshot) {
    return ChildEntity( 
      snapshot.documentID,
      snapshot.data['label']);
  }
}

【问题讨论】:

    标签: flutter dart google-cloud-firestore stream


    【解决方案1】:

    我想这就是你想要的:

    Stream<List<Parent>> jots2() {
      return parentsCollection.snapshots().asyncMap((snapshot) async {
        return Future.wait(snapshot.documents.map((doc) async {
          var parentEntity = await ParentEntity.fromSnapshot(doc);
          return Parent.fromEntity(parentEntity);
        }).toList());
      });
    }
    

    诀窍是使用asyncMap(类似于map,但异步)和Future.wait(等待所有Futures 完成)来异步处理QuerySnapshot。

    几点说明:

    • 你可能错过了.toList() 毕竟.map
    • 使用此方法,如果仅更改子项的值,您的 Stream 不会发出新值,但如果您更新父项,它会发送更新的子项
    • 因为这样您总是会阅读父级的完整子级集合,这可能会影响您的 Firestore 使用,因为它是基于每个文档的

    您还要求提供“好”样品。不幸的是 - 这取决于您的数据和应用程序。 Firebase 提出了一个关于结构化数据的whole page。有时最好避免子集合,有时则不然。

    在您的情况下,将“孩子”作为数据字段 (children2) 而不是子集合似乎更有意义,但我不完全知道您在创建什么。

    【讨论】:

      【解决方案2】:

      您将Stream&lt;List&lt;Parent&gt;&gt; 声明为类型,但.map().toList() 组合返回List&lt;dynamic&gt;。您需要在地图上声明类型:

      return Future.wait(snapshot.documents.map<Parent>((doc) async {
      

      【讨论】:

        猜你喜欢
        • 2017-03-25
        • 2022-12-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-01-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多