how to read a single files in firebase - firebase

so i want to read the roles of my users, i know how to read collection and document,but how to read a field from the documents?
this what i've been trying,
#override
void readRole(){
final path = APIPath.role(uid);
final reference = FirebaseFirestore.instance.collection(path);
final snapshots = reference.snapshots();
snapshots.listen((snapshot) { snapshot.docs.forEach((snapshot) => print(snapshot.data()));
});
}
static String role (String uid) => 'users/$uid';

Firestore doc.data() has type of Map<String, dynamic> , meaning Json.
so you could try something like this:
final Map<String, dynamic> data = snapshot.data();
final String role = data['role'];
But the best way would be to create a user entity and use Json_serializable: https://pub.dev/packages/json_serializable
and convert the firestore data object to your user entity;
But by checking your role() function, i am not sure to understand it correctly, user's role is just the string 'users/$uid' ?

Related

Listen to changes and get info on updated fields only

I have Flutter/Firebase app, which allows users to store their book reading data into Firestore (books completed reading, reading currently etc). I would like to implement a feature, which allows users to see if someone completes reading a book (FS volume object field "completedUsers" updates) or someone starts reading a new book (FS account object field "nowReading" updates).
I think I should be using CollectionReference().snapshots().listen() - method for this, but I haven't figured out how and how to set it up with StreamBuilder, so I could get exact info on which part of db object was updated.
Here are my models on user account and volume:
#JsonSerializable(explicitToJson: true)
class Account {
String name;
String uid;
List<Volume> nowReading;
List<Volume> wantToRead;
List<Account> friends;
Map<String, Volume> tips;
Account(
{this.name,
this.uid,
this.nowReading,
this.wantToRead,
this.friends,
this.tips});
factory Account.fromJson(Map<String, dynamic> json) =>
_$AccountFromJson(json);
Map<String, dynamic> toJson() => _$AccountToJson(this);
}
#JsonSerializable(explicitToJson: true)
class Volume {
String id;
String title;
String description;
String smallThumbnail;
String bigThumbnail;
List<String> authors;
List<String> categories;
int published;
int pageCount;
double averageGoogleRating;
double averageUserRating;
List<UserReview> userReviews;
List<String> completedUsers;
Volume(
{this.id,
this.title,
this.description,
this.smallThumbnail,
this.bigThumbnail,
this.authors,
this.categories,
this.published,
this.pageCount,
this.averageGoogleRating,
this.averageUserRating,
this.userReviews,
this.completedUsers});
factory Volume.fromJson(Map<String, dynamic> json) => _$VolumeFromJson(json);
Map<String, dynamic> toJson() => _$VolumeToJson(this);
}
Firestore notifies clients when a document has changed, but not what specific fields within that document have changed. If you application needs that information, you will have to compare the previous DocumentSnapshot and the new version yourself in your application code.

Getting a list of friends and then displaying a friends list

I'm struggling with how I can get the data of a user's friends from Firebase's Realtime Database to build it out in Flutter. The structure of the database looks like this:
enter image description here
Essentially, in my code, I'm listening to changes in an user's friends list from the database and then getting the friend ID so that I can query the rest of the friend's metadata (image, name, etc.) to build out the friend's list in the app. The issue I'm running into is that I can't seem to get the Json data to map correct and I get the following error:
Unhandled Exception: type '_InternalLinkedHashMap<dynamic, dynamic>' is not a subtype of type 'String'
Any insight would be appreciated
class _FriendsScreenState extends State<FriendsScreen> {
#override
void initState() {
getUserFriendsList();
super.initState();
}
getUserFriendsList() async {
rtdb.child('friends').child(widget.currentUserID).onValue.listen((event) {
final data = new Map<String, dynamic>.from(event.snapshot.value);
data.keys.forEach((element) async {
DataSnapshot userInfo = await usersRef.child(element).get();
User users = User.fromJson(json.decode(userInfo.value));
});
});
}
factory User.fromJson(Map<String, dynamic> parsedJson) {
return User(
imageUrl: parsedJson['userImageUrl'],
userFirstName: parsedJson['userFirstName'],
userLastName: parsedJson['userLastName'],
userID: parsedJson['userID'],
);
}
I think you have a problem in:
User users = User.fromJson(json.decode(userInfo.value));
why u have used JSON decode (json.decode & User.fromJson) twice?
However, for further analysis, you should provide data and log it.
There's no need to decode the json as DataSnaphot.value "returns the contents of [the] data snapshot as native types."
So userInfo.value does not return a String, it returns a Map instead.
Solution:
Convert the result to a Map<String, dynamic> from the _InternalLinkedHashMap<dynamic, dynamic> type it returns.
Change this line:
User users = User.fromJson(json.decode(userInfo.value));
to this:
User users = User.fromJson(Map<String, dynamic>.from(userInfo.value));

How to store map data in array with Flutter Firestore

I try to make an app about health blog with Flutter. I want to store some data with arrays that contain map data. Although I can manually perform this on the Firestore, I'm getting some errors in coding.
Here is Firestore screenshot
Here is the code which I try to add map data to the array.
Future<bool> updateUserCases(String userId, Map newCase) async {
await _firestoreDB.collection("users").doc(userId).update({
"userCases" : FieldValue.arrayUnion([newCase])
});
return true;
}
I can add my map data to Firestore, but when I try to add it to the array, I get this error.
E/flutter (10661): [ERROR:flutter/lib/ui/ui_dart_state.cc(186)] Unhandled Exception: [cloud_firestore/unknown] Invalid data. FieldValue.serverTimestamp() can only be used with set() and update()
And this is my "Case Model" which I want to add into the array
class CaseModel {
final String caseId;
final String caseTitle;
final String caseBody;
final Map caseOwner;
Timestamp caseDate;
bool caseSolve;
List<String> casePhotos;
String caseTag;
CaseModel(
{#required this.caseOwner,
this.caseId,
this.caseTitle,
this.caseBody,
this.caseDate,
this.caseTag});
Map<String, dynamic> toMap() {
return {
"case_id": caseId,
"case_title": caseTitle,
"case_body": caseBody,
"case_owner": caseOwner,
"case_date": caseDate ?? FieldValue.serverTimestamp(),
"case_solve": caseSolve,
"case_photos": casePhotos,
"case_tag": caseTag,
};
}
Could you help if there is a way I can fix this problem? Thank you.

Store array from cloud firestore into variable

I have a collection called users. Each document has the ids of posts they have saved in an array. Is it possible to put this array into a variable and have it in a Text() widget? Essentially the text widget output would look like this on screen oMqSYa97CteaDr19lZ5Ga6WO4jn8oPJREOcJWLI2.
I have searched for this solution, but haven't found any luck.
I've tried a few things, but usually end up with Instance of 'Future DocomentSnapshot'
you should share your code for us to learn what you did and why do you face with that oMqSYa97CteaDr19lZ5Ga6WO4jn8oPJREOcJWLI2. However, firstly, you should create a model like that
class UserData {
final String uid;
final String name;
final String sugars;
final int strength;
UserData({ this.uid, this.sugars, this.strength, this.name });
}
and an instance;
final CollectionReference UsersCollection =
FirebaseFirestore.instance.collection('users');
and you can use it like that ;
UserData _userDataFromSnapshot(DocumentSnapshot snapshot) {
return UserData(
uid: uid,
name: snapshot.data()['name'],
sugars: snapshot.data()['sugars'],
strength: snapshot.data()['strength'],
);
}
Stream<UserData> get userData {
return UsersCollection.doc(uid).snapshots().map(_userDataFromSnapshot);
}
finally;
UserData userData = snapshot.data.sugars;

Firestore query to variable to populate shared preferences

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

Resources