Firestore query to variable to populate shared preferences - firebase

New to Flutter, and although I've been around code for many years, this is my first time actually developing. I've been trying to figure out how to query the Cloud Firestore and map one of those properties to a shared preference. Since my app is talking to the cloud firestore when a user logs in anyway, I feel like I can update my shared preferences with a few fields that will save me from having to call firestore everytime I want to retrieve that piece of information.
I created a class that represents the collection layout in the firestore
class FirestoreUser {
FirestoreUser(this.aboutMe, this.nickname);
final String aboutMe;
final String nickname;
factory FirestoreUser.fromMap(Map<String, dynamic> data) {
if (data == null) {
return null;
}
final String aboutMe = data['aboutMe'];
final String nickname = data['nickname'] ?? '';
return FirestoreUser(aboutMe, nickname);
}
Map<String, dynamic> toMap() {
return {
'aboutMe': aboutMe,
'nickname': nickname,
};
}
}
I also have a function that writes data to the Firestore collection. That works just fine.
What I'm having a hard time with is how do I query for "aboutMe" in the collection above? I'm using
a provider to get the uid, but how do I do something like this:
aboutMe = Firestore.query.tothatdocument
Here's what I have been working on so far:
final user = Provider.of<User>(context, listen: false);
final firestore = Provider.of<FirestoreService>(context, listen:false);
final firebaseUser = await FirebaseAuth.instance.currentUser();
final QuerySnapshot result = await Firestore.instance.collection('users').where('id', isEqualTo: firebaseUser.uid).getDocuments();
final List<DocumentSnapshot> documents = result.documents;
SharedPreferences prefs = await SharedPreferences.getInstance();
And I want to do something like this:
prefs.setString('aboutMe', 'thatAboutMeVariable);
Is this possible? I think I'm missing capturing the stream as a snapshot? but not to sure.
Thanks again!

I ended up creating a new class with functions to retrieve the fields that I wanted. I then assigned a variable to the results of that function.
Here's the call:
aboutMe = await FirestoreUserService(id: widget.id).getAboutMeFromFirestore();
Here's the class and function:
class FirestoreUserService {
FirestoreUserService({#required this.id});
final FirebaseFirestore firestore = FirebaseFirestore.instance;
CollectionReference users;
String aboutMe;
Future getAboutMeFromFirestore() async {
DocumentSnapshot ds = await FirebaseFirestore.instance.collection('users').doc(id).get();
aboutMe = ds.data()['aboutMe'];
//print('\nFirestore aboutMe is value: $aboutMe');
return aboutMe;
}
}

Related

How do I filter data from cloud firestore twice?

I want to check if a user has a string ’Level' with any number in his document.
Level: int
If this is the case, the future should return true and false if not.
That’s the code I’m trying it with:
class StufenService{
String userID;
StufenService(this.userID);
final CollectionReference userTodos =
FirebaseFirestore.instance.collection('userTodos');
Future checkIfStufeExists() async {
await userTodos.where('Stufe' is int).get();
final data = QuerySnapshot.data.documents.where(userID);
if (data.exists){
return true;
} else
{return false;}
}
}
First I filter out all users who have ’Level': int in their firebased document. Then I want to check if the current user is among the users.
The data after the QuerySnapshot is underlined in red:
The getter 'data' isn't defined for the type 'QuerySnapshot'.
Can someone help me to implement my plan?
Maybe the whole thing has to be done differently?
For cases like this, I find it most useful to keep the FlutterFire documentation and Firestore reference handy. Based on those, you code should be something like:
final CollectionReference userTodos =
FirebaseFirestore.instance.collection('userTodos');
Future checkIfStufeExists() async {
var query = userTodos.where('Stufe', isEqualTo: 42); // First condition
query = query.where("userId", isEqualTo: userID); // Second condition
final querySnapshot = await query.get(); // Read from the database
return querySnapshot.size > 0; // Check if there are any results
}
You are not doing anything with the returned value of the where statement.
The class QuerySnapshot does not have .data static getter. In order to access the returned value from firestore you need to do something like that:
...
final snapshot = await userTodos.where('Stufe' is int).get();
final data = snapshot.data;
...

How to get data from instance user_type by uid (Firebase flutter)

How to get data from instance user_type by uid (Firebase flutter)
Create a variable for your users collection
final CollectionReference _usersCollection =
FirebaseFirestore.instance.collection("users");
Query user document snapshot based on the userId value
final QuerySnapshot<Object?> usersQuery = await _usersCollection.where("uid",isEqualTo: userId).limit(1).get();
You can get your Map data from the document snapshot
if(usersQuery.length>0) {
final Map<String, dynamic> userData =
usersQuery.docs[0].data() as Map<String, dynamic>;
return userData['userType']; // you can use the data as you wish here am returning it
}
// else do something when the data isn't available
final _firestoreInstance = FirebaseFirestore.instance;
// returns a list of user documents
final res = await _firestoreInstance.collection("user_type").get();
// returns the first user_type instance of the list
final firstUser = res.docs.first.data();
return firstUser['uid'];

Failed to get uid to use within DatabaseService class in flutter

I face a problem where I can't get the current user ID from my firebase. I've already make that every new user will have their own collection based on the UID like this:
void addImagetoFirestore() async {
final CollectionReference imageData = Firestore.instance.collection(uid);
This is my DatabaseService class
class DatabaseService {
final String uid;
DatabaseService({this.uid});
String useruid;
final FirebaseAuth auth = FirebaseAuth.instance;
//Collection reference
final CollectionReference warrantyCollection =
Firestore.instance.collection('user id here');
List<Picture> _warrantyListFromSnapshot(QuerySnapshot snapshot) {
return snapshot.documents.map((doc) {
return Picture(
name: doc.data['product name'],
info: doc.data['info'],
url: doc.data['url'],
uid: doc.data['uid']);
}).toList();
}
Future updateUserData(String name) async {
return await warrantyCollection.document(uid).setData({'name': name});
}
Stream<List<Picture>> get picture {
return warrantyCollection.snapshots().map(_warrantyListFromSnapshot);
}
}
I've tried referring to this,
but it seem like I can't just make something like
final CollectionReference warrantyCollection = Firestore.instance.collection(useridmethod());
are there any other alternative that I can try?
Instead of getting uid as a parameter to class, fetch it in constructor because in your case final FirebaseAuth auth = FirebaseAuth.instance; is useless as I see.
try this;
DatabaseService(){
userId = auth.currentUser.uid;
}

Flutter & Firestore : How do I get all of the DocumentID from Firestore?

How do I get all of the DocumentID from Firebase and put them into a list.
Stream <List<String>> getMaterial(BuildContext context) {
final CollectionReference materialColection =
Firestore.instance.collection('materials');
return ???????;
}
other file
List<String> _material = [-------]
I'm looking forward to hearing from you. Thank you.
You can try this,
Future <List<String>> getMaterial(BuildContext context) async {
List<String> ids =[];
final CollectionReference materialColection =
Firestore.instance.collection('materials');
final result = await materialColection.get(); //getDcouments() for < firebase: ^0.14
result.docs.forEach((doc){
ids.add(doc.id) //doc.documentId for < firebase: ^0.14
});
return ids;
}
This will return the list of ids of the document each time you call the function.
Alternatively, if you want to listen to the stream, it would be best to Warp it in a StreamBuilder() and extract the document ids within the widget

How to assign a Future variable to a class getter in Flutter

I'm trying to read user data from Firebase via Streamer and assign them into properties of my User class. I have a FirabaseActions class doing firebase stuff. Here is the method that I use streamer to get data. It works perfectly, and print(user.data['userName']); give me the right result.
static Future<User> userDataStream(loggedInUserEmail) async {
final databaseReference = Firestore.instance;
User currentUser;
await for (var snapshot in databaseReference
.collection('users')
.where('email', isEqualTo: loggedInUserEmail)
.snapshots()) {
for (var user in snapshot.documents) {
print(user.data['userName']);
currentUser.userName = user.data['userName'];
currentUser.email = user.data['email'];
currentUser.userID = user.data['userID'];
currentUser.level = user.data['level'];
}
}
return currentUser;
}
The problem begin when I try to assign these user info to my class properties. Here is my User class. I got an error like below. It is about Future type but I can't handle it. What should I do?
Class 'Future' has no instance getter 'email'.
Receiver: Instance of 'Future'
Tried calling: email
class User {
String userName;
String userID;
String email;
int level;
User({this.userName, this.userID, this.level, this.email});
}
The first problem is that you cant assign an username like this
currentUser.userName = user.data['userName'];
Because currentUser is null. A simple solution to that is to replace
User currentUser; with User currentUser = User();
Second problem :
I think you should never search user by his email, rather by the UID that you get from
FirebaseUser user = await FirebaseAuth.instance.currentUser(),
So you would query for the user like this :
static Future<User> userDataStream() async {
final firestore = Firestore.instance;
final currentFirestoreUser = await FirebaseAuth.instance.currentUser();
User currentUser;
var query = await firestore
.collection('users')
.where('uid', isEqualTo: currentFirestoreUser.uid)
.getDocuments();
var user = query.documents.first.data;
currentUser = User(
userName: user['userName'],
userID: user['userID'],
level: user['level'],
email: user['email']);
return currentUser;
}
You could add UID as a method's parameter, or leave it inside the method.

Resources