I am new to flutter and firestore development.
I have a collection of posts. For each post I have sub-collection of feedback. Feedback can be good or bad. What I want to do is get sum of good and bad feedbacks.
Here I am displaying all my posts with good and bad feedback count.
I can get the posts and the feedback inside each of them. But I don't know how to add feedback to posts. Or calculate the sum.
Stream<List<Post>> get myPosts {
Query query = Firestore.instance
.collection('posts')
.where("userId", isEqualTo: uid)
.orderBy('modifiedDate', descending: true);
final Stream<QuerySnapshot> snapshots = query.snapshots();
return snapshots.map((QuerySnapshot snapshot) {
List<Post> postList = snapshot.documents.map((doc) {
Firestore.instance
.collection('posts')
.document(doc.documentID)
.collection('feedback')
.getDocuments()
.then((allFeedbackDocs) => {
allFeedbackDocs.documents.forEach((feedbackDoc) {
var feedData = feedbackDoc.data;
})
});
return Post.fromMap(doc.data, doc.documentID);
}).toList();
return postList;
});
}
Ideally what I want to do is supply good and bad feedback count to "Post.fromMap"
Can someone provide some help on this?
Based on @Sukhi answer tried this, but getting errors. Keep getting no data, even there's a document
If I understand this correctly, if there is no "feedbackCount" doc I have to add it. If there is one I have to update the count.
var feedBackRef = Firestore.instance
.collection('posts')
.document('fiCv95srzMufldYb15zw')
.collection('feedbackCount')
.document();
Firestore.instance.runTransaction((transaction) async {
transaction.get(countryRef).then((result) => {
if (result.exists)
{print('has data')}
else
{print('no data')}
});
});
With the help provided by @Sukhi. I came up with this;
Future<void> updateFeedbackCount(
DocumentReference feedbackRef, int good, int bad, String docId) async {
var postRef =
Firestore.instance.collection(APIPath.posts()).document(docId);
await Firestore.instance.runTransaction((transaction) async {
await transaction.get(postRef).then((res) async {
if (!res.exists) {
throw PlatformException(
code: 'POST_FOR_FEEDBACK_NOT_FOUND',
message: "Could not found post for the feedback.",
);
}
var goodCount = res.data['good'] + good;
var badCount = res.data['bad'] + bad;
transaction.update(postRef, {
'good': goodCount,
'bad': badCount,
});
});
});
}
@override
Future<void> addFeedback(UserFeedback feedback, String postId) async {
var postRef =
Firestore.instance.collection(APIPath.feedback(postId)).document();
await postRef.setData(feedback.toMap()).then((result) =>
updateFeedbackCount(postRef, feedback.good, feedback.bad, postId));
}
Aggregating all documents (.forEach) and calculating sum may be 'costly' - both in terms of performance and money since Firestore charge is based on number reads, write, delete operations. Now, if you have 1000 documents and 100 mobile app users then the number of read operations would be 1000 x 100 = 100,000 on every single day. And with each additional document, the read count will increase by 100.
One way to deal with it is to maintain another document with the count. So, the document will just contain two counts as
goodCount:40
badCount:11
Check out this Firestore documentation or this quick tutorial on how to do it.
** Thanks Frank for the documentation link.