Reputation: 1344
I want to read nested fields from my firestore. The hierarchy of the fields is
comments
|__ c_id
|__ c_text
|_________replies
|____________ r_id
|____________ r_text
I tried the following code:
var documentSnapshot = await FirebaseFirestore.instance
.collection("article_engagements")
.doc(id.toString())
.get();
var comments = await FirebaseFirestore.instance
.collection("article_engagements")
.doc(id.toString())
.collection("comments")
.get();
comments.docs.forEach((element) {
var replies = element.get('replies');
commentsList.add(Comment(
id: element.get('c_id'),
text: element.get('c_text'),
replies: ,
));
});
article = new ArticleEngagement(
id: id,
likes: documentSnapshot.get('likes'),
shares: documentSnapshot.get('shares'),
comments: commentsList,
);
But i am stuck at getting the replies field. Screenshot of the firestore document is as follows:
The ArticleEngagement, comment and replies models are as follows:
class ArticleEngagement {
int? id;
int? likes;
int? shares;
List<Comment>? comments;
ArticleEngagement({
this.id,
this.likes,
this.shares,
this.comments,
});
}
class Comment {
String? id;
String? text;
List<Reply>? replies;
Comment({
this.id,
this.replies,
this.text,
});
}
class Reply {
String? id;
String? reply;
Reply({
this.id,
this.reply,
});
}
Upvotes: 1
Views: 847
Reputation: 1214
The problem was that you wanted to access the comments
field as if it were a subcollection of the article_engagements
document, but, in fact, it is an array.
To access all your fields inside the document given a certain id
, I would suggest mapping your fields as nested classes that reflect your actual data structure. As pointed out by this answer,
You can use the json_serializable package, which generates code for serializing/deserializing.
Creating model classes the json_serializable way
Ensure that your class attributes match your fields in Cloud Firebase
import 'package:json_annotation/json_annotation.dart';
/// This allows the `ArticleEngagement` class to access private members in
/// the generated file. The value for this is *.g.dart, where
/// the star denotes the source file name.
part 'test.g.dart';
/// An annotation for the code generator to know that this class needs the
/// JSON serialization logic to be generated.
@JsonSerializable()
class ArticleEngagement {
int? article_id;
int? likes;
int? shares;
List<Comment>? comment;
ArticleEngagement({
this.article_id,
this.likes,
this.shares,
this.comment,
});
/// A necessary factory constructor for creating a new ArticleEngagement instance
/// from a map. Pass the map to the generated `_ArticleEngagement()` constructor.
/// The constructor is named after the source class, in this case, ArticleEngagement.
factory ArticleEngagement.fromJson(Map<String, dynamic> json) =>
_$ArticleEngagementFromJson(json);
/// `toJson` is the convention for a class to declare support for serialization
/// to JSON. The implementation simply calls the private, generated
/// helper method `_$ArticleEngagementToJson`.
Map<String, dynamic> toJson() => _$ArticleEngagementToJson(this);
}
@JsonSerializable()
class Comment {
String? c_id;
String? c_text;
List<Reply>? replies;
Comment({
this.c_id,
this.replies,
this.c_text,
});
factory Comment.fromJson(Map<String, dynamic> json) =>
_$CommentFromJson(json);
Map<String, dynamic> toJson() => _$CommentToJson(this);
}
@JsonSerializable()
class Reply {
String? r_id;
String? r_text;
Reply({
this.r_id,
this.r_text,
});
factory Reply.fromJson(Map<String, dynamic> json) => _$ReplyFromJson(json);
Map<String, dynamic> toJson() => _$ReplyToJson(this);
}
Then you have to run the code generation utility.
One-time code generation
By running
flutter pub run build_runner build
in the project root, you generate JSON serialization code for your models whenever they are needed.
Finally, you can consume json_serializable models, like this:
var document = await FirebaseFirestore.instance
.collection("article_engagements")
.doc(id.toString())
.get();
ArticleEngagement article =
ArticleEngagement.fromJson(document.data() as Map<String, dynamic>);
print(article.comment?.first.c_id);
See also:
Upvotes: 1