Getting a valid value from StreamBuilder<DocumentSnapshot> and a child StreamBuilder - flutter

I am trying to get a specific icon to appear based on whether the user has taken the survey or not.
At the moment, I am using StreamBuilder to listen for a given value in a document, which returns the survey name. I then want to use the survey name in the next StreamBuilder, which will look in a given collection (which is made up of the survey name followed by _entrants - so, for example, Survey_entrants) for a completed survey document, which will have the title of the user's unique id (named userid).
The problem I have now is that whilst surveyName does return the name of the survey put in Cloud Firestore, and updates it when I change the value (I can see this by the commented-out return new Text('$surveyName'); command).
However, it does not seem to be passing that value into the next StreamBuilder - regardless of what I put in as the survey name, I get the check icon showing, suggesting (snapshot1.hasData) - even when that document does not exist.
I know the surveyName variable is working, but if I do snapshot1.toString() I get the error Snapshot(ConnectionState.active, Instance of 'DocumentSnapshot', null). This must count has having data, hence showing the survey being taken. How do I correct this?
My code:
Positioned(
right: 30,
top: 20,
child: StreamBuilder<DocumentSnapshot>(
stream: Firestore.instance
.collection('Controller')
.document('Current Survey')
.snapshots(),
builder: (BuildContext context,
AsyncSnapshot<DocumentSnapshot> snapshot) {
if (!snapshot.hasData) {
return CircularProgressIndicator();
} else {
var sn = snapshot.data;
surveyName = sn["cs"];
// return new Text('$surveyName');
return StreamBuilder(
stream: Firestore.instance
.collection('$surveyName' + '_entrants')
.document(userid)
.snapshots(),
builder: (BuildContext context, snapshot1) {
if (!snapshot1.hasData) {
return Icon(
Foundation.burst_new,
size: 48,
color: Color(0xff303841),
);
} else if (snapshot1.hasData) {
return Icon(
Foundation.check,
size: 48,
color: Color(0xff303841),
);
} else {
return Icon(
MaterialIcons.error_outline,
size: 48,
color: Color(0xff303841),
);
}
});
}
})),

The issue I had was that Cloud Firestore returns a DocumentSnapshot even when there is nothing in the database to return. So, I changed (snapshot1.hasData) to (snapshot1.data.exists) and this works as expected - the icon changes based on the response.

Related

how to get document id index on firestore with flutter onTap method

I am trying to get the document ID. I don't know if it is the right way, but until now I could manage to get all the IDs.
Then I am trying to get the document ID index so I can open the category with onTap and show the category products.
I have tried with map, forEach, etc... but nothing.
return Scaffold(
body: StreamBuilder(
stream: firestore.snapshots(),
builder:(context, snapshot){
if (snapshot.connectionState == ConnectionState.waiting)
return Center(child: CircularProgressIndicator());{
final document = snapshot.data?.docs;
return ListView.builder(
itemCount: document?.length,
itemBuilder: (context, index) {
return Center(
child: Column(
children: [
InkWell(
onTap: (){
FirebaseFirestore.instance.collection('prova').get()
.then((QuerySnapshot querySnapshot) {
querySnapshot.docs.map((doc) {
print(doc.id);
var docId = doc.id;
Navigator.push(context, MaterialPageRoute(builder: (context)=>
CategoriesPage(document: document[index]['name'], docId: docId)));
});
});
As I mentioned in my comment, the way FireStore allows you to store data is alternating between collections and docs. That's to say you can't put another doc into a doc, and another collection within a collection. You can only put docs in a collection, and then subcollections within a doc, etc, etc.
I'm unaware of your data structuring needs, however I'd suggest something like this:
When a user creates a category, simply add it to their doc, and then any products within the category could be placed into a sub-collection under that category. Let me know if that could work for you.

How to recover a specific data in the firestore?

I have this structure in the database:
I have a function that return the current user logged
FirebaseAuth auth = FirebaseAuth.instance;
auth.currentUser.uid;
And i want to retrieve "requisicoes" when "idUser" == auth.currentUser.uid;
Basically, the user retrieves the requests created by himself.
That's my StreamBuilder
final _controller = StreamController<QuerySnapshot>.broadcast();
FirebaseFirestore db = FirebaseFirestore.instance;
StreamBuilder<QuerySnapshot> addListenersRequests() {
final stream = db
.collection("requisicoes")
.where("usuario.idUser", isEqualTo: idUsuarioLogado)
.snapshots();
stream.listen((dados) {
_controller.add(dados);
});
return null;
}
Note: idUsuarioLogado is returning correctly currentUser
The problem is that I am getting everything in the "requisicoes" collection, when I create a new user, other users' requests appear on the screen
is there a logic problem in StreamBuilder?
As per you problem ,I think you are fetching the data of your current logged uid .But You want to retrieve the details of particulers users created(i,e documendId) . Then you have to fetch documentId first.Like
body: StreamBuilder(
stream:users.snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
}
if(!snapshot.hasData){
return Center(
child: CircularProgressIndicator(),
);
}
return ListView(
children: snapshot.data.documents.map((document) {
return Center(
child: Container(
width: MediaQuery.of(context).size.width/2.5,
height: MediaQuery.of(context).size.height/5,
child: Text(document.id),
),
);
}).toList());
}),
You have to fetch document.id. This is your particuler user instead of this.
FirebaseAuth auth = FirebaseAuth.instance;
auth.currentUser.uid;
Note: This will return you current logged userId.
For more details gothrough thislink.
I found the answer here Firestore is ignoring the where clause in the query in flutter
My example is the same as the link above, I have two functions, one addListenersRequests() and the other getCurrentUser(), these two functions I was calling in the initState method, the problem is that getCurrentUser is async, so addListenersRequests () was being executed first, before the value of the variable idUsuarioLogado is filled.
So I merged the two functions into one, so that getCurrentUser can be executed first
Final code:
Future<StreamBuilder<QuerySnapshot>> addListenersRequests() async{
await getDataUser();
final stream = db
.collection("requisicoes")
.where("usuario.idUser", isEqualTo: idUsuarioLogado)
.snapshots();
stream.listen((dados) {
_controller.add(dados);
});
return null;
}
Now it is working correctly.
The strange thing about this story is that the firebase executes the clause and retrieves everything in the collection even when the referenced variable is null

Firestore Flutter How Sort Data using int fields

Hello i have a firestore db with structure
Root
.....Oder
.........Xyz1
______T:1
.........Xyz1
______T:1
when i get the data i want it to sort automatically in desending oder using the int value stored in 'T'
T is unique for every document
child: StreamBuilder(
stream: Firestore.instance.collection("Oder").snapshots(),
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) {
return new Text('Loading...');
}
return new ListView(
reverse: true,
children: snapshot.data.documents.map((document) {
return new ListTile(
title: new Text(document['T'].toString()),
);
}).toList(),
);
},
),
This is my code here
I also have the same value of T as String as each document name so sorting with that gave me 1,10,11,2,3...
So i need to get sorted with the int value stored in T
This is
You can get the data with this line:
CollectionReference collectionReference = Firestore.instance.collection("data-collection");
But , you can get the ordered data with:
Query collectionReference = Firestore.instance.collection("data-collection").orderBy('field');
orderBy should returns a Query, you can no longer store it as a CollectionReference.

Flutter StreamBuilder<DocumentSnapshot> not passing value into child StreamBuilder

I am trying to get a specific icon to appear based on whether the user has taken the survey or not.
At the moment, I am using StreamBuilder<DocumentSnapshot> to listen for a given value in a document, which returns the survey name. I then want to use the survey name in the next StreamBuilder, which will look in a given collection (which is made up of the survey name followed by _entrants - so, for example, Survey_entrants) for a completed survey document, which will have the title of the user's unique id (named userid).
The problem I have now is that whilst surveyName does return the name of the survey put in Cloud Firestore, and updates it when I change the value (I can see this by the commented-out return new Text('$surveyName'); command).
However, it does not seem to be passing that value into the next StreamBuilder - regardless of what I put in as the survey name, I get the check icon showing, suggesting (snapshot1.hasData) - even when that document does not exist.
I know the surveyName variable is working, but if I do snapshot1.toString() I get the error Snapshot<DocumentSnapshot>(ConnectionState.active, Instance of 'DocumentSnapshot', null). This must count has having data, hence showing the survey being taken. How do I correct this?
My code:
Positioned(
right: 30,
top: 20,
child: StreamBuilder<DocumentSnapshot>(
stream: Firestore.instance
.collection('Controller')
.document('Current Survey')
.snapshots(),
builder: (BuildContext context,
AsyncSnapshot<DocumentSnapshot> snapshot) {
if (!snapshot.hasData) {
return CircularProgressIndicator();
} else {
var sn = snapshot.data;
surveyName = sn["cs"];
// return new Text('$surveyName');
return StreamBuilder(
stream: Firestore.instance
.collection('$surveyName' + '_entrants')
.document(userid)
.snapshots(),
builder: (BuildContext context, snapshot1) {
if (!snapshot1.hasData) {
return Icon(
Foundation.burst_new,
size: 48,
color: Color(0xff303841),
);
} else if (snapshot1.hasData) {
return Icon(
Foundation.check,
size: 48,
color: Color(0xff303841),
);
} else {
return Icon(
MaterialIcons.error_outline,
size: 48,
color: Color(0xff303841),
);
}
});
}
})),

How to use setState for just one widget

I have a Future which takes a value from my Cloud Firestore database and displays an icon in the body of my app. If the value in the database changes, the icon updates. I have been using setState to rebuild my widget tree and this works fine - the app reacts almost instantly to changes in my Cloud Firestore database. This is great! Code:
Future<void> takenSurvey2() async {
final sn = await Firestore.instance
.collection('Controller')
.document('Current Survey')
.get();
surveyName2 = sn['cs'];
final snapShot = await Firestore.instance
.collection('$surveyName2' + '_entrants')
.document(userid)
.get();
if (snapShot.exists) {
takenSurvey = true;
} else {
takenSurvey = false;
}
setState(() {});
}
and the place where the icon is shown is coded like this (within a stack):
Positioned(
right: 30,
top: 20,
child: FutureBuilder(
future: takenSurvey2(),
builder: (context, snapshot) {
if (takenSurvey == false) {
return Icon(
Foundation.burst_new,
size: 48,
color: Color(0xff303841),
);
} else if (takenSurvey == true) {
return Icon(
Foundation.check,
size: 48,
color: Color(0xff303841),
);
} else
return Container();
})),
However, I've added in my AdMob adverts using the 'admob_flutter' package, and because setState seems to be constantly running, the advert cannot load - I just see a flashing box. If I remove setState from the code above, the adverts load, but the icons in my app do not update when the value in Cloud Firestore changes.
How do I either exclude my admob_flutter widget from setState, or just use setState (or something else) to only update my FutureBuilder widget? I would like to do so in a way which limits the number of calls on Cloud Firestore, but this is not essential.
Thanks!