I am using geoflutterfire package to get all documents within a certain radius. I am trying to display each document through a model class in a listview. I have my Firestore database structured as:
The code for my StreamBuilder is
buildTimelinePosts() {
return StreamBuilder<List<DocumentSnapshot>>(
stream: geo
.collection(
collectionRef: FirebaseFirestore.instance.collection('posts'))
.within(
center: geo.point(latitude: -1.3998973, longitude: 36.767642),
radius: 5000,
field: 'position'),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return circularProgress();
}
snapshot.data!.forEach((doc) {
nearbyListings.add(Post.fromDocument(doc));
});
return ListView(
children: nearbyListings,
);
},
);
}
Why am I still getting zero documents even when they are within the radius?
As far as I can see, userPosts is a subcollection and not a top-level collection. To be able to display user posts within a given geographic area, you have to specify all intermediate references. So a reference like this it will be required:
.collection(collectionRef: FirebaseFirestore.instance
.collection('posts')
.doc('109298...')
.collection('userPosts'))
Related
I am using geoflutterfire to get documents of a location within a certain radius. I would like the results to be put into a model class and then each displayed in a listview.
Here's my trial (Still a rookie so it's probably all wrong anyway)
buildTimelinePosts() {
return StreamBuilder(
stream:
geo.collection(
collectionRef: FirebaseFirestore.instance.collection("userPosts"))
.within(center: geo.point(
latitude: position.latitude, longitude: position.longitude),
radius: 50,
field: 'position'),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return
circularProgress();
}
List<Post> units = [];
snapshot.data.documents.forEach(doc){
units.add(Post.fromDocument(doc));
};
return ListView(children: units,);
},
);
}
I'm getting the error The getter 'documents' isn't defined for the type 'Object'
How do I go about this?
Hey guys I have two top level collections, a user and a tabs collection. Within each user document I have an array field of document ids with each element in the array representing a document in the tabs collection (sort of like a reference or a pointer to that document) and I would like to listen to real time changes in the users/document with the list of ID's and to listen for changes to the corresponding documents in the tabs collection.
Below is my code so far and there are two issues with it. The stream isn’t working client side - I’m not receiving an updated snapshot when I update the document in cloud firestore. Also in order for me to get a list of tabIds I am currently making a query to cloud firestore which returns a stream however, the whereIn operator only accepts a list of objects so I’m not to sure how to handle that.
data model screenshot
Stream<List<Tab>> get tabs {
var tabIds = _db.collection('users').doc(user.uid).snapshots().where((event) => event.get('tabs'));
return _db
.collection('tabs')
.where(FieldPath.documentId, whereIn: tabIds)
.snapshots()
.map((list) =>
list.docs.map((doc) => Tab.fromJson(doc.data())).toList());
}
You can't directly listen to documents based on their ids, but you can add a field called docId (the value should be the id of the document) to each document then listen to collection with this where condition.
List listOfDocIds = []; // this is the list of your docIds
StreamBuilder<QuerySnapshot<Map<String, dynamic>>>(
stream: FirebaseFirestore.instance
.collection('users')
.where('docId', whereIn: listOfDocIds),
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot<Map<String, dynamic>>> snapshot) {
if (snapshot.hasError) return Text('Something went wrong');
if (snapshot.connectionState == ConnectionState.waiting)
return CircularProgressIndicator();
List<Map<String, dynamic>> data =
snapshot.data.docs.map((e) => e.data()).toList();
print(data);
// you can build your widget here
return ListView.builder(
itemCount: data.length,
itemBuilder: (context, i) {
return ListTile(
title: Text(data[i]['name']),
// TODO: change 'name' to name of field in users document
);
},
);
},
),
In my App I use a Streambuilder to show a list of plans that are stored in Firestore (every plan has its own document) on a screen:
final CollectionReference planCol = FirebaseFirestore.instance.collection('users').doc(FirebaseAuth.instance.currentUser.uid).collection('plans');
body: StreamBuilder(
stream: planCol.snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
final planDocs = snapshot.data.docs;
return ListView.builder(
itemCount: planDocs.length,
itemBuilder: (context, index) => MyListTile(
title: Text(planDocs[index]['name']),
trailing: IconButton(
icon: Icon(Icons.edit),
onPressed: () {
edit(planDocs[index]);
},
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return ExerciseTable(
plan: UserPlan(
name: planDocs[index]['name'],
exerciseNames: planDocs[index]
['exerciseNames'],
rows: planDocs[index]['rows'],
planId: planDocs[index].id,
),
);
},
),
);
}),
);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
}));
On this screen, I only want to show the name of each document and not all the other data which is stored in the document(because they are very big). Now I was asking myself how efficient Streambuilder works when each document is very big. Does it load the whole document or only the field of the document, that is needed?
On this screen I only want to show the name of each document and not all the other data which is stored in the document(because they are very big).
All Cloud Firestore listeners fire on the document level. So there is no way you can get only the value of a single field in a document. That's the way Firestore works.
Now I was asking myself how efficient Streambuilder works when each document is very big.
It's more about the time that it takes to download those documents.
Does it load the whole document or only the field of the document, that is needed?
It loads the entire document.
If you need only some names, you should consider storing those names in a single document. In this case, you can read only one document and you have to pay only one read.
I have made flutter streambuilder that creates a flutter listview from results returned from a query.
StreamBuilder<QuerySnapshot>(
stream: _usersStream,
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading");
}
return ListView(
scrollDirection: Axis.horizontal,
children: snapshot.data!.docs.map(
(DocumentSnapshot document) {
Map<String, dynamic> data =
document.data()! as Map<String, dynamic>;
addChildBtn();
return ListCard(
firstName: data['childFirstName'],
lastName: data['childLastName'],
points: data['points'],
);
},
).toList(),
);
},
),
It returns a listCard, a custom widget I made which consists of a container. However, I want to have a container always in the listview, regardless if there any items returned from the steam or not.
I have the same exact question. did you find an intelegent away for that?
my workaround which is not super, I added one document in firestore with specfic name, then in the list view builder I check for the name, if matched I return my fixed customized item, if doesn't match then I return the regular card.
the result is what you want, the constrain is that if you have different categories in your firestore database, then you will need to add this specific document everywhere.
I want to get the id of every document in a collection. i tried this code but it return a single document id unlimited times. Can you please suggest a correction or a alternative
getrequest() {
linkref.document(uuid).
collection("Requests").getDocuments().then((value) async{
value.documents.forEach((doc) {
user.add(doc.documentID);
});},);
return ListView.builder(
itemBuilder: (BuildContext cntxt, int index){
return Text(user[index]);
});
}
there is a collection inside a document and inside this collection i have other document. i want to retrieve all documents id
This is screenshot of my firestore
Currently, you have just one document in firestore. I would suggest you add multiple documents and then test this command.You can use snapshot to get multiple documents as suggested by Sandeep using
Firestore.instance
.collection('Links')
.document(docID)
.collection('Requests')
.snapshots();
You can retrieve multiple documents with one request by querying documents in a collection. By default, Cloud Firestore retrieves all documents that satisfy the query in ascending order by document ID, but you can order and limit the data returned. To retrieve the documents conditionally using where() and then use get
More can be found in the documentation here
To use ListView builder, I would suggest using StreamBuilder something like this:
StreamBuilder<DocumentSnapshot>(
stream: Firestore()
.collection('homepage')
.document(widget.user.uid)
.collection('h')
.document(todaysDate())
.snapshots(),
builder: (context, snapshot) {
if (snapshot.data != null) {
snapshot.data.data.forEach((index, individualDetail) {
cardDetails[index] = individualDetail;
});
}
return cardDetails == null
? CircularProgressIndicator()
: ListView.builder(
itemBuilder: (context, index) {
return HomepageCards(
user: widget.user,
cardDetails:
cardDetails[cardDetails.keys.toList()[index]],
);
},
itemCount: (cardDetailKeys == null
? 0
: cardDetailKeys.length),
);
},
)
This is a snippet from my code but the StreamBuilder would look similar for you too.
Firestore.instance
.collection('Links')
.document(docID)
.collection('Requests')
.snapshots();