I have two collection in firestore question
and bookmark
.
for saving a question to users bookmarks page , my approach for structuring database was to set the documents docID
of bookmark collection to be same as of question collections documents docID
and field of bookmark collection is only one that is uid of user who is saving the bookmark my structure looks like this,
this is my bookmark collection
this is my question collection
here bookmark documents ID == question document ID
so far I have used streambuilder but not able to fetch the question documents from bookmark collection, this is my code so far and I aint getting how to get question documents from bookmarks collection docID
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:devcom/screens/detailsPage.dart';
import 'package:devcom/utils/responsive.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
class Bookmark extends StatefulWidget {
final User user;
const Bookmark({Key? key, required this.user}) : super(key: key);
@override
State<Bookmark> createState() => _BookmarkState();
}
class _BookmarkState extends State<Bookmark> {
@override
void initState() {
_currentUser = widget.user;
super.initState();
}
late User _currentUser;
// final db = FirebaseFirestore.instance;
@override
Widget build(BuildContext context) {
final Stream<QuerySnapshot> _bmStreams = FirebaseFirestore.instance
.collection('bookmark')
.where("uid", isEqualTo: "${_currentUser.uid}")
.snapshots(includeMetadataChanges: true);
return StreamBuilder<QuerySnapshot>(
stream: _bmStreams,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Text('Something went wrong');
}
if (snapshot.hasData == false)
return Text(
'Howdy ${_currentUser.displayName}!!, 404 clever: you havent posted in a while');
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading");
}
return Scaffold(
appBar: AppBar(
title: Text('My Questions'),
leading: IconButton(
onPressed: () {
Navigator.pop(context);
},
icon: Icon(Icons.arrow_back_ios_new_rounded)),
),
backgroundColor: Colors.white,
body: Padding(
padding: EdgeInsets.all(40),
child: ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, int index) {
final DocumentSnapshot data = snapshot.data!.docs[index];
if (!data.exists) {
print('not exists');
}
return Text(data['mydatahere']);
},
)));
},
);
}
}
and is it possible to nest streambuilder or do I need to fetch documents separtely please help I am badly stuck at this and dont know how to make this work...
thank you,
CodePudding user response:
Yes, you can nest streamBuilders.
For each bookmark, we fetch it the question corresponding to that id.
Replace your listView builder with below.
itemBuilder: (context, int index) {
final DocumentSnapshot data = snapshot.data!.docs[index];
if (!data.exists) print('not exists');
// here we return the second StreamBuilder
return StreamBuilder<DocumentSnapshot<Map<String, dynamic>>>(
stream: FirebaseFirestore.instance
.collection('question')
.doc(data.id)
.snapshots(),
builder: (BuildContext context,
AsyncSnapshot<DocumentSnapshot<Map<String, dynamic>>>
qSnapshot) {
if (qSnapshot.hasError) return Text('Something went wrong');
if (qSnapshot.connectionState == ConnectionState.waiting)
return Text("Loading");
print(qSnapshot.data!.data()); // should print the question
return Text(data['mydatahere']);
},
);
},
There are some drawbacks with your document structure.
- If 2 users bookmark the same question, it will only retain one of their bookmarks. An easy way around this is to make uid (in bookmarks collection) an array of uids. If a user bookmarks the question, you add him to the array using this
FieldValue.arrayUnion(uid)
and if he un-bookmarks, you remove him withFieldValue.arrayRemove(uid)
and to fetch all data for a user, you use.where('uids', arrayContains: uid)
. - Also, It might be better to simply have an array in the questions collection called
usersThatBookmarked
where you add users that have bookmarked a question. This is not optimal but it should be better than my first suggestion - Also, I do not think you should stream bookmarks collection. The user should not be able to add a bookmark while he's on the bookmark page. Therefore, it is better to use a future to fetch the bookmarks collection. This should improve performance.
- To avoid documents reaching the 1mb limit and to avoid collision (1), you can use the document id for the
bookmarks
collection asuid '_' questionId
(This prevents a user from bookmarking a question twice). Then add the fieldsuid
andquestionId
to eachbookmark
document. You can fetch usingwhere('uid', isEqualTo: uid)
andquestionId
will be the question document id.