I have a firestore database with a hierarchical relationship. The "Parent" document has a collection ("children") of child objects. I want to have a stream of Parent objections. So if the parent changes in Fire store the stream should offer a new Parent object with all the children loaded.
The code below is what I am trying to achieve. The problem is in the line marked "====> Problem", which in inserted into the code.
The compiler says : The return type 'List>' isn't a 'List', as defined by anonymous closure.dart(return_of_invalid_type_from_closure).
I don't know how to convert this stream to "map" call to an asyn call to get a List instead of a Future
Anyone know a good sample for hierarchical Firestore data in Flutter/Dart?
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']);
}
}
I think this is what you are asking for:
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());
});
}
The trick is to use asyncMap
(which is like map, but async) and Future.wait
(which waits for all Futures to complete) to asynchronously process QuerySnapshot.
Few notes:
.toList()
after all .map
Você também pediu uma amostra "boa". Infelizmente - isso depende de seus dados e aplicativo. O Firebase criou uma página inteira sobre estruturação de dados. Às vezes é melhor evitar subcoleções, às vezes não.
Parece que, no seu caso, ter seus "filhos" como campo de dados (filhos2) em vez de subcoleção faz mais sentido, mas não sei exatamente o que você está criando.
Este artigo é coletado da Internet.
Se houver alguma infração, entre em [email protected] Delete.
deixe-me dizer algumas palavras