如何从 Firestore 制作父/子对象流
Posted
技术标签:
【中文标题】如何从 Firestore 制作父/子对象流【英文标题】:How can I make a stream of parent/child objects from 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']);
【问题讨论】:
【参考方案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<List<Parent>>
声明为类型,但.map()
与.toList()
组合返回List<dynamic>
。您需要在地图上声明类型:
return Future.wait(snapshot.documents.map<Parent>((doc) async
【讨论】:
以上是关于如何从 Firestore 制作父/子对象流的主要内容,如果未能解决你的问题,请参考以下文章
Java流对象:InputStreamOutputStreamReaderWriter
即使流正在返回对象,Flutter StreamProvider 也会返回 null 对象