Getting a map from Firestore and setting it to a new map - flutter

I have two methods the first one for getting a map stored in Firestore
Future daysMap(FirebaseUser user, String packageCode, int totalDays) async {
await users.document(user.uid).collection('myPackages')
.document(packageCode)
.get().then((doc){
// print(doc.data['DaysMap']);
return doc.data['DaysMap'];
});
}
It works correctly and prints out the map. The second method is for setting the map from Firestore to a new map in order to loop on it.
currentWorkout(FirebaseUser user, String packageCode,totalDays) async {
Map<dynamic, dynamic> days = await daysMap(user, packageCode, totalDays);
print(days);
}
When i print our the new map 'days' it always prints null.

Try using the async/await style.
Future daysMap(FirebaseUser user, String packageCode, int totalDays) async {
DocumentSnapshot doc = await users.document(user.uid).collection('myPackages').document(packageCode).get();
return doc.data['DaysMap'];
}

Related

Unexpected text "return" inside function

int FriendsNum() {
_firestore.collection('Friends').doc(User.userID).collection("Friends").where("Status",isEqualTo: 2)
.get()
.then((res)=> return{res.size});
return 0;
}
I am basically trying to get the number of documents that are inside the collection that has the status of 2, and the value should be returned so it can be displayed for the user, what can be changed in the syntax to make this work? with many thanks!
You have to change your function return type to a Future and use the await keyword to get the result from the firestore collection as it is an asynchronous operation itself.
The updated code will be the following:
Future<int> FriendsNum() async {
final count = await _firestore
.collection('Friends')
.doc(User.userID)
.collection("Friends")
.where("Status",isEqualTo: 2)
.get()
.then((res) => res.size);
return count;
}

Future<dynamic> is not a subtype of List<dynamic>

So I am trying to pass a list of String values from firestore table, but I am getting an exception type 'Future<dynamic>' is not a subtype of type 'List<dynamic>'
This is the function
getLectureList(String userId) async {
var collection = FirebaseFirestore.instance.collection('students');
var docSnapshot = await collection.doc(userId).get();
Map<String, dynamic>? data = docSnapshot.data();
List<String> _lectureList =
await data!['attendance']; //This line is kinda giving me trouble
userInfo = FirestoreWrapper()
.getStudentFromData(docId: currentUser(), rawData: data);
return _lectureList;
}
And this is the function where I am getting the exception thrown
#override
void initState() {
lectureList = getLectureList(currentUser()); // Getting an exception here
NearbyConn(context).searchDevices(devices: deviceList);
super.initState();
}
tried using await in the getLectureList() method but still getting the same problem
Why do you await your data? You already got it.
List<String> _lectureList = data!['attendance'];
Please note that I don't know what your data structure looks like, so I cannot tell you if this is correct, I can only tell you that it is more correct than before, because the await did not belong there.
You are getting an exception here lectureList = getLectureList(currentUser()); because the the parameter required by the getLectureList() method is the userId which is a string. I do not know what currentUser() return but I'm assuming it's the userId that you need when calling the getLectureList() method. Based on the error, it looks like currentUser() is an async method that returns a future after some time.
You're not awaiting that future. You shouldn't make the initState() method async so move the code block out of it into a separate method and then call it from initState().
Something like this,
#override
void initState() {
super.initState();
_getData();
}
void _getData() async {
lectureList =
getLectureList(await currentUser());
NearbyConn(context).searchDevices(devices: deviceList);
}
or
#override
void initState() {
super.initState();
_getData();
}
void _getData() async {
String _userID = await currentUser();
lectureList = getLectureList(_userID);
NearbyConn(context).searchDevices(devices: deviceList);
}
Which I recommend so you can see all the parts.
Making your method parameters required named parameters also help you to easily see what is needed to pass to a function/class/.
Eg.
getLectureList({required String userId}){
...
}
Your IDE will alert you on the type of object the function requires and it makes things clearer.
Ultimately, I think typing your classes makes it so much more easier to fetch data from fireStore Typing CollectionReference and DocumentReference
This way you can easily do this,
final moviesRef = FirebaseFirestore.instance.collection('movies').withConverter<Movie>(
fromFirestore: (snapshot, _) => Movie.fromJson(snapshot.data()!),
toFirestore: (movie, _) => movie.toJson(),
);
and get your data this way,
Future<void> main() async {
// Obtain science-fiction movies
List<QueryDocumentSnapshot<Movie>> movies = await moviesRef
.where('genre', isEqualTo: 'Sci-fi')
.get()
.then((snapshot) => snapshot.docs);
// Add a movie
await moviesRef.add(
Movie(
title: 'Star Wars: A New Hope (Episode IV)',
genre: 'Sci-fi'
),
);
// Get a movie with the id 42
Movie movie42 = await moviesRef.doc('42').get().then((snapshot) => snapshot.data()!);
}
Keeps everything dry and tidy.
< The data comes to list format thats why showing the exception of datatype >
List<String> lectureList = await getLectureList(currentUser()); // use
Future<List<String>> getLectureList(String userId) async {
- your code -
}
Instead of
List _lectureList =
await data!['attendance'];
Try this
_lectureList = await data![] As List

How to return a List, after a Method fills it, Flutter

I'm stuck with a problem and I wondered if you can help me.
I have a functions (in Flutter) that returns a List of Items. Now this List of Items should be Filled by an other function, which goes thought my Database and collect the right items. My Problem is, that my Function runs after the Return Statement... Here is some Code:
Future<List<MaterialItem>> getItems(String path, String fach) async {
// This is a empty List that I want to fill
List<MaterialItem> list = [];
// That's my Function, that fills the List
var result = await _db
.collection("$path/$fach/")
.get()
.then((QuerySnapshot querySnapshot) {
querySnapshot.docs.forEach((doc) {
// Here the List gets filled
list.add(MaterialItem.fromSnapshot(doc.data() as Map<String, dynamic>));
});
});
// Here the List should be returned, but after my Function fills it.
return list;
}
Hope you know what my problem is, and someone can help me.
I think you could solve this using a Completer. Your function should return the Future property of the Completer and the database call should then complete it.
Take a look at the API and the example:
https://api.dart.dev/stable/2.12.4/dart-async/Completer-class.html
For example: (pseudo code)
Future<List<MaterialItem>> getItems(String path, String fach) async {
// declare a completer
Completer<List<MaterialItem>> completer = Completer();
List<MaterialItem> list = [];
final result = await _db
.collection("$path/$fach/")
.get()
.then((QuerySnapshot querySnapshot) {
querySnapshot.docs.forEach((doc) {
list.add(MaterialItem.fromSnapshot(doc.data() as Map<String, dynamic>));
});
// let the database call complete the completer
completer.complete(list);
});
// return the future value of the completer
return completer.future;
}

How to send Map<String,bool> to cloud Firestore in Flutter

We have a Map declared as follows:
Map<String, bool> _selection = {};
It contains data as follows:
key = 'Messi'
value = 'true'
We wanted to send the data containing in the Map _selection.
Right now we are trying using a method defined as given below:
Future<Map<String, dynamic>> votedown() async {
_selection.forEach((key, value) {
Map<dynamic, dynamic> comdata = <dynamic, dynamic>{
'criteriaName': key,
'isChecked': value,
};
return comdata;
});
}
We are sending data to firestore as:
DocumentReference ref =
FirebaseFirestore.instance.collection('posts').doc();
await ref.set({
'Players': {
'Football': {
await votedown(),
}
}
});
But it is giving error as:
ArgumentError (Invalid argument: Instance of '_CompactLinkedHashSet<Map<String, dynamic>>')
Please help me to solve this?
Desired Output in Firestore in 'posts' collection:
--> Players
--> Football
--> PlayerName : Messi
isStriker : true
It seems the problem is in brackets {} surrounding the await downvote(). As the method is returning a map object already, if you put into the brackets you will have set of map nested object. Such objects are not in types available in the Firestore (reference) and this is reason of the error.
I do not have a playground to test it, but please try bellow:
DocumentReference ref =
FirebaseFirestore.instance.collection('posts').doc();
await ref.set({
'Players': {
'Football': await votedown(),
}
});

async map doesnt reflect changes in the method body

The list returned from this code is empty. assume that formatUser is an async method that formats the user from the remote to a suitable format. why is that filterUsers list does'nt change when we map the other list?
Future<List<User>> fetchUsers() async{
final list<User> usersFromRemote = await getUserFromRemote();
final List<User> filterUsers = [];
usersFromRemote.map((user) async {
if(user.name != 'jim')
{
filterUsers.add(await formatUser(user));
}
});
return filterUsers;
}
You are using map wrongly. You need to use filter(aka where) and map for your use case.
Future<List<User>> fetchUsers() async {
final List<User> usersFromRemote = await getUserFromRemote();
final List<User> filterUsers = await Future.wait(
usersFromRemote.where((u) => u.name != 'jim').map(
(user) async {
return formatUser(user);
},
),
);
return filterUsers;
}
Or you can use forEach but which is not very functional.
Use forEach() instead of map(). According to the docs, unless the iterable returned by map() is iterated over, the transforming function will not be called.