如何从 Firestore 制作父/子对象流

thr*_*rag 1 stream dart flutter google-cloud-firestore

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

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

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

我不知道如何将此流转换为对异步调用的“映射”调用以获取列表而不是未来

有人知道 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']);
  }
}
Run Code Online (Sandbox Code Playgroud)

pr0*_*ist 5

我想这就是你要问的:

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());
  });
}
Run Code Online (Sandbox Code Playgroud)

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

几点注意事项:

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

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

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

Firestore 面板