I want to return my all documents in firestore my document in Identifier based on name but when I do my function its return to me With the same number I have documents but the name its different instance of DocumentSnapshot but I need to return same names I have. How can I do this? Below is the code I am using
Widget build(BuildContext context) {
// TODO: implement build
return StreamBuilder < QuerySnapshot > (
stream: Firestore.instance.collection("Institute")
.document(widget.id).collection("Ravs").snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
print('list of docment:${snapshot.data.documents.toList()}');
};
return CircularProgressIndicator();
}
);
}
The Instance of DocumentSnapshot log is saying that you are interacting with the Snapshot object itself. which is what your code is indeed doing.
To get access to the data inside the Snapshot you have to add the .data() call next to your Snapshot, so your stream should look like this:
stream: Firestore.instance.collection("Institute").document(widget.id)
.collection("Ravs").snapshots().data()
Related
I managed to get one data from Firebase Realtime Database. This time I want to turn it into JSON format and get two data at least. Below is the code
my Database Reference
`
DatabaseReference ref =
FirebaseDatabase.instance.ref().child('UsersData/$userDataUID/test/int');
my code `
StreamBuilder(
stream: ref.onValue,
builder: (context, snapshot) {
if (snapshot.hasData) {
debugPrint(snapshot.data?.snapshot.value.toString());
}
return const CircularProgressIndicator();
})),
my Firebase console
I believe I have to convert it into Maps? I have no idea how to begin with
Try with
DatabaseReference ref =
FirebaseDatabase.instance.ref().child('UsersData/$userDataUID/test');
This will return a map with those fields.
And use on widget like
if (snapshot.hasData) {
final map = snapshot.data?.snapshot.value as Map?;
return Text("int: ${map?["int"]} voltage: ${map?["voltage"]}"); }
Find more about getting data
I have an app where admin can delete all documents in the firebase collection and add an x number of new documents, this works beautifully, but my streambuilder isn't updating properly,
the stream builder is getting back only one document everytime you delete all documents and create new ones, it only returns one, and like when you leave the app and come back, it fetches the proper amount of documents, all I can find online is that it's wrong to use a loop when querying and I've removed my for loop and am now using the map method, still, it is the same, here is my stream builder code
StreamBuilder<QuerySnapshot>(
stream: _store.collection("picks").snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
List<PickCard> pickCards = [];
final documentSnapshots = snapshot.data!.docs;
debugPrint(documentSnapshots.length.toString());
if (documentSnapshots.isNotEmpty) {
documentSnapshots.map((e) {
pickCards.add(
PickCard(
pickerPosition: e["pickerPosition"],
pickerName: e["pickerName"],
isPicked: e["isPicked"],
pickerEmail: e["pickerEmail"],
),);
}).toList();
dHelp.setCards(
context,
pickCards,
);
dHelp.setContributors(context, documentSnapshots.length);
}
} else {
}
the print document snapshot length is always 1 when they get created, but after refresh, the actual length updates, but in the firebase console, everything works perfectly, the documents update effectively,
here is a video of the problem https://www.dropbox.com/s/25qqnh0ttgemgf1/2022-08-16%2010-26-46.mp4?dl=0
I found that passing the stream directly to the streamBuilder was causing the stream to restart each time the build method rebuilt, which was supposed to be whenever the stream returns new data, so, it was kinda knotting over itself,
I instantiated the stream in the state then passed it to the streamBuilder, so now it's only created once in the lifetime of the page
// created this variable
late Stream<QuerySnapshot> _stream;
#override
initState() {
// gave it a value in iniState
_stream = _store.collection("picks").snapshots();
super.initState();
}
StreamBuilder<QuerySnapshot>(
stream: _stream, // then added this here
builder: (context, snapshot) {
if (snapshot.hasData) {
List<PickCard> pickCards = [];
final documentSnapshots = snapshot.data!.docs;
debugPrint(documentSnapshots.length.toString());
if (documentSnapshots.isNotEmpty) {
documentSnapshots.map((e) {
pickCards.add(
PickCard(
pickerPosition: e["pickerPosition"],
pickerName: e["pickerName"],
isPicked: e["isPicked"],
pickerEmail: e["pickerEmail"],
),);
}).toList();
dHelp.setCards(
context,
pickCards,
);
dHelp.setContributors(context, documentSnapshots.length);
}
} else {
}
currently i'm using firestore and realtime database at the same time. I set and retrieve from firestore in the most simplest and effective way in code and for realtime database i set data but i couldn't retrieve it in the same way that i do with firestore.
Summary i want to do the same thing which i do with firestore code in realtime database code.
Here is my code:
//Get data from Firestore
Stream <DocumentSnapshot> getData() async*{
final user = FirebaseAuth.instance.currentUser;
yield* FirebaseFirestore.instance.collection('users').doc(user.uid).snapshots();
}
//Return data in StreamBuilder (No lists or ListView.Builder needed here)
#override
Widget build(BuildContext context) {
return StreamBuilder(
stream: getData(),
builder: (context, snapshot) {
//--------------------------------------
//These equations comes from Firestore
//--------------------------------------
int currentWater ()=> snapshot.data['currentLitersAmount'];
int remainingWater () => snapshot.data['currentLitersAmount'] <= snapshot.data['recomendedLitersAmount'] ? snapshot.data['recomendedLitersAmount'] - snapshot.data['currentLitersAmount'] : 0;
double progress ()=> snapshot.data['currentLitersAmount'] / snapshot.data['recomendedLitersAmount'];
So how to do the same thing here for realtime database?
The equivalent of your getData function for Realtime Database would be:
Stream <Event> getData() async*{
final user = FirebaseAuth.instance.currentUser;
yield* FirebaseDatabase.instance.reference().child('users').child(user.uid).onValue();
}
And you can then get the DataSnapshot from each Event object in your UI building code.
#override
Widget build(BuildContext context) {
return StreamBuilder(
stream: getData(),
builder: (context, snapshot) {
int currentWater ()=> snapshot.data.snapshot.value['currentLitersAmount'];
...
If that snapshot.snapshot looks confusing, have a look at What is the difference between existing types of snapshots in Firebase?
I'm try to get sub collection from each doc ex.clothes,notifer witch I have more docs , that means I don't know its id ,My bossiness Logic was to fetch the main collection for getting all the documents and then for each doc get its sub collection and I did that with Future implementation ,but I can't do it using Stream to return the final Sub Collection SnapShots ex.properitres for listing to changes . by Future it rebuild every time and if I stop widget rebuilding by AutomaticKeepAliveClientMixin I could not get any Firesotre changes . Thanks in advance .
here is my Future implementation but again I need this implementation by Stream ^_^:
Future<List<Category>> getPropertiesDocs() async {
List<QueryDocumentSnapshot> _firstListOfDocs = [];
List<Category> _categorListOfDocs = [];
List<QueryDocumentSnapshot> _secoudListOfDocs = [];
final QuerySnapshot result = await _firebaseFirestore.collection('categories').get();
result.docs.forEach((element) {
// print(element.id);
_firstListOfDocs.add(element);
});
for (var i in _firstListOfDocs) {
final QuerySnapshot snapshot2 = await i.reference.collection("properties").get();
snapshot2.docs.forEach((element) {
_secoudListOfDocs.add(element);
_categorListOfDocs.add(Category.fromSnapShpt(element));
});
}
_firstListOfDocs.clear();
_secoudListOfDocs.clear();
return _categorListOfDocs;
}
From your future implementation,
You want to get all documents in categories collection.
For each document in categories collection, you want to get the properties subcollection.
For the first requirement, we can simply stream the categories collection.
For the second requirement, it is not advisable to stream properties collection from each categories subcollection. This won't scale well with large datasets.
Instead we will stream the collectionGroup properties. Streaming the collection group properties will fetch all collections with the name properties (no matter the location). To effectively use this, no other collection should be named properties (except the ones you want to fetch), or you rename your collection to something distinct like properties_categories.
// this streamBuilder will fetch stream for categories collection.
StreamBuilder<QuerySnapshot>(
stream: _firebaseFirestore.collection('categories').snapshots(),
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot<Delivery>> snapshot) {
if (snapshot.hasError) return Message();
if (snapshot.connectionState == ConnectionState.waiting)
return Loading();
print('categories snapshot result');
print(snapshot.data.docs.map((e) => e.data()).toList());
// _firstListOfDocs is given below (renamed to _categoryDocs)
List<QueryDocumentSnapshot> _categoryDocs = snapshot.data.docs;
// this streamBuilder will fetch all documents in all collections called properties.
return StreamBuilder<QuerySnapshot>(
stream: _firebaseFirestore.collectionGroup('properties').snapshots(),
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> propertiesSnapshot) {
if (propertiesSnapshot.hasError) return Message();
if (propertiesSnapshot.connectionState == ConnectionState.waiting)
return Loading();
print('properties snapshot result');
print(propertiesSnapshot.data.docs.map((e) => e.data()).toList());
// _secoudListOfDocs is given below (and renamed to _propertiesDocs)
List<QueryDocumentSnapshot> _propertiesDocs = propertiesSnapshot.data.docs;
// _categorListOfDocs is given below (and renamed to _categories)
List<Category> _categories = propertiesSnapshot.data.docs
.map((e) => Category.fromSnapShpt(e)).toList();
// return your widgets here.
return Text('Done');
},
);
},
)
If your reason for fetching categories collection data is simply to loop over it and fetch properties collection, then you can delete the first streamBuilder above since we do not need to use it to fetch properties collection.
I have a simple question. The reference to my firestore collection is dynamic. In this piece of code, getDocumentReference() gives me a reference to document after checking the user's email.
I use this document reference to get my snapshots.
Future<Stream<QuerySnapshot>> getHabits() async {
DocumentReference document = await getDocumentReference();
var snapshots = document.collection('habits').snapshots();
return snapshots;
}
As you can see, I want to use this Future<Stream<QuerySnapshot>> for a streambuilder. How can I do that? I tried something like this. But it is not taking the future as input to stream
return StreamBuilder(
stream: getHabits(),
);
You can wrap it in a FutureBuilder:
return FutureBuilder<Stream<QuerySnapshot>>(
future: getHabits(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return StreamBuilder(stream: snapshot.data); // Success
} else if (snapshot.hasError) {
return Text('${snapshot.error}'); // Error
} else {
return CircularProgressIndicator(); // Loading
}
},
);