Firestore Class 'QuerySnapshot' has no instance method '[]' - flutter

I want a ListView to show the names of the users. I am using a cloudfunction with the admin sdk to return a list of all the users with the corresponding user IDs. When I want to pass that uid to a Widget with a streambuilder, it gives me the error:
Class 'QuerySnapshot' has no instance method '[]'.
Receiver: Instance of 'QuerySnapshot'
Tried calling: []("firstName")
This is the function I am calling while building the ListView for the title:
Widget getFirstName(uid, item) {
return StreamBuilder(
stream: Firestore.instance
.collection('users')
.document('HzBUMs06BAPHK0Y7m5kfOmUzawC2')
.collection('userInfo')
.snapshots(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
return Text('${item['email']}');
} else {
return Text('${snapshot.data.documents['firstName']}');
}
},
);
}
I am not using the uid which I will pass to it yet, as the User ID that I hardcoded right now is the only one with the firstName data in it.
When I feed it a non-existing userID, it still seems to think it has data in it and tries to return its (non-existent) data.
What am I doing wrong here?

I managed to fix it by using this piece of code:
Widget fullNameWidget(uid) {
return FutureBuilder(
future: fullName(uid),
builder: (context, snapshot) {
return Text('${snapshot.data}');
},
);
}
Future fullName(uid) async {
return Firestore.instance
.collection("users")
.document('$uid')
.collection("userInfo")
.getDocuments()
.then((querySnapshot) {
print(querySnapshot.documents[0]['firstName']);
if (querySnapshot == 'null') {
} else {
return '${querySnapshot.documents[0]['firstName']} ${querySnapshot.documents[0]['lastName']}';
}
// querySnapshot.documents.where((element) {
// print(element.documentID == 'firstName');
// });
});
}

Related

Nested StreamBuilders Flutter

So I'm currently using this nest of two streams, one to listen for AuthStateChanges, to know if the user is logged in, and another that listens to a firebase document snapshot request, to know if the user has already setup is account or not.
My problem is that the latter StreamBuilder(_userStream) only runs if the firts one runs, meaning that the only way for my _userStream to run is if the user either logs in or logs out(authStateChanges Stream).
This is inconvinient because after the user creates an account(moment where i run Auth().createUserWithPasswordAndEmail()), I need the user to go throw the process of seting up the account, and only after that the user can acess the mainPage. Only in the end of seting up the account theres a button to "Create Account", which changes the "HasSetupAccount" parameter in firebase to true. But because of the nested Streams problem, the app doesn't go to the mainPage until I force update it.
I hope my question is not as confusing as it looks :)
class _WidgetTreeState extends State<WidgetTree> {
#override
//construtor da class?
Widget build(BuildContext context) {
return StreamBuilder(
stream: Auth().authStateChanges,
builder: (context, snapshot) {
if (snapshot.hasData) {
return StreamBuilder(
stream: _userStream(),
builder:
((context, AsyncSnapshot<DocumentSnapshot> userSnapshot) {
if (userSnapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator();
} else {
Map<String, dynamic> userData =
userSnapshot.data!.data() as Map<String, dynamic>;
print(userSnapshot.data!.data().toString());
if (userData['HasSetupAccount'] == true) {
return MyHomePage();
} else {
return AccountSetup();
}
}
}));
} else {
return LoginPage();
}
},
);
}
Stream<DocumentSnapshot<Map<String, dynamic>>> _userStream() {
return FirebaseFirestore.instance
.collection('Users')
.doc(Auth().currentUser!.uid)
.snapshots();
}
}

Flutter: Bad state: cannot get a field on a DocumentSnapshotPlatform which does not exist

I am trying to log in with two different types on flutter firebase. I tried too many things but still, I couldn't do it. In the end, I found another solution but I got new errors.
Bad state: cannot get a field on a DocumentSnapshotPlatform that does not exist.
StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if(snapshot.hasData && snapshot.data != null) {
return StreamBuilder<DocumentSnapshot>(
stream: FirebaseFirestore.instance.collection("users").doc(snapshot.data!.uid).snapshots() ,
builder: (BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot){
if(snapshot.hasData && snapshot.data != null) {
final userDoc = snapshot.requireData;
// final user = userDoc.data();
if(userDoc.get('role') == 'admin') {
return AdminPage();
}else{
return Home();
}
}else{
return Material(
child: Center(child: CircularProgressIndicator(),),
);
}
},
);
}
return LoginPage();
}
);
I'm doing an app with two logins. Patients and doctors. Doctors can control patients or smth like that. So doctors should be admins. I made two login options. Admin login and user login. But if I can do it on the same login page, it would be good.

flutter orderBy("time", "asc") not working

i am using nested stream and future to get 2 sets of data, but cannot sort the second set of data by time
Tried both but still not working.. why???
Error: Getter not found: 'Direction'.
.orderBy("time", Query.Direction.DESCENDING)
^^^^^^^^^
Error: Too many positional arguments: 1 allowed, but 2 found.
Try removing the extra positional arguments.
.orderBy("time", 'asc')
^
full code below:
return StreamBuilder(
stream: A,
builder: (context, snapshot) {
return snapshot.hasData
? ListView.builder(
...
return
FutureBuilder(
future: FirebaseFirestore.instance
.collection("some path here")
.orderBy("time", Query.Direction.DESCENDING)
.get(),,
builder: (context, snapshot2) {
if (snapshot2.hasData) {
if (snapshot2.data!=null) {
return DisplayTile(
...
);
}
}
return CircularProgressIndicator();
}
);
})
: Container();
},
);
orderBy has 1 named parameter called descending of bool type to pass order.
Example from docs:
FirebaseFirestore.instance
.collection('users')
.orderBy('age', descending: true) // here
.get()
.then(...);

Creating Stream for StreamBuilder with Firestore

I'm have created a Stream that it working inside StreamBuilder, but I have to pass some parameters to my Stream, this parameters are in a dart file which only has functions. I'm attempting to create the same code that was working, but passing the user uid.
This is what I attempted:
Stream<QuerySnapshot> main_page_stream() async*{
final FirebaseUser user = await _auth.currentUser();
Stream stream = Firestore.instance.collection('user_data').
document(user.uid).collection('Buttons').snapshots();
await for(var event in stream) {
yield event.documents;
}
}
I get the following error:
Exception has occurred.
NoSuchMethodError (NoSuchMethodError: Class 'QuerySnapshot' has no instance getter 'snapshot'.
Receiver: Instance of 'QuerySnapshot'
Tried calling: snapshot)
This isn't working on the home page:
StreamBuilder(
stream: _auth.main_page_stream(),
builder: (context, snapshot) {
if (snapshot.hasError){
return Container(color: Colors.red);
}
if (!snapshot.hasData){
print(snapshot.data);
return Center(child: CircularProgressIndicator());
}
if (snapshot.hasData){
var screenSize = MediaQuery.of(context).size.width;
return Stack(
children: [
this was working:
stream: Firestore.instance.collection('user_data').document('sdsajnd82173812').collection('Buttons').snapshots(),
The QuerySnapshot - event doesn't have a field snapshot. Instead you have to
yield event;
And for this the function return you the Stream<QuerySnapshot>.

Flutter firestore streambuilder with a future

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
}
},
);