Flutter - Firstore returns null data even when data is there - flutter

I have the data which stored in firestore database. But when I try to fetch the data it returns null.
Here is the code,
Future<Map<String, dynamic>> getDocumentInfo(String collectionName, String docId) async {
DocumentSnapshot document = await FirebaseFirestore.instance.collection(collectionName).doc(docId).get();
print(document.data());
Map<String, dynamic> docInfo = document.data() as Map<String, dynamic>;
return docInfo;
}
Can anyone say what is the error? It gives the error "_CastError (type 'Null' is not a subtype of type 'Map<String, dynamic>' in type cast)"

Check if something related to this works ... it's not a snapshot but it'll give you the idea.
Future<void> addNewQuestion(Map AddQuestionData, File image) async {
CommanDialog.showLoading();
var pathimage = image.toString();
var temp = pathimage.lastIndexOf('/');
var result = pathimage.substring(temp + 1);
final ref = FirebaseStorage.instance.ref().child('').child(result);
var response = await ref.putFile(image);
var imageUrl = await ref.getDownloadURL();
CommanDialog.hideLoading();
try {
CommanDialog.showLoading();
var response = await firebaseInstance.collection('QuestionList').add({
'QuestionId': AddQuestionData['QuestionId'],
'QuestionText': AddQuestionData['QuestionText'],
"QuestionImageURL": imageUrl,
'AnswerA': AddQuestionData['AnswerA'],
"AnswerB": AddQuestionData['AnswerB'],
"AnswerC": AddQuestionData['AnswerC'],
"AnswerD": AddQuestionData['AnswerD'],
"AskedIn": AddQuestionData['AskedIn'],
"SubjectName": AddQuestionData['SubjectName'],
"ChapterName": AddQuestionData['ChapterName'],
"CorrectAnswer": AddQuestionData['CorrectAnswer'],
});
CommanDialog.hideLoading();
Get.back();
} catch (exception) {
CommanDialog.hideLoading();
}
}

Related

Future not waiting to resolve before next then Flutter Dart

I'm trying to return a list of values.
Assessing by using Late
late List userLikes = userListLikes.getUsersLikes();
My Code:
class GetUserLikes {
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
final user = FirebaseAuth.instance.currentUser!;
List getUsersLikes() {
try {
print('start');
final docRef = _firestore.collection("user_details").doc(user.uid);
docRef.get().then((DocumentSnapshot doc) async {
final data = doc.data() as Map<String, dynamic>;
print("data[user_likes]");
print(data['user_likes']);
print('end');
return await data['user_likes']; // → not awaiting
},
onError: (e) => print("Error getting document: $e"),
);
} catch (err) {
print('There was an error');
}
return ['Nothing Returned'];
}
}
The function is not completing and returns before the await has finished which is not the array I need.
start
[Nothing Returned] (Returns without completing)
data[user_likes]
[967, 769, 887, 820, 860, 833, 857, 1017] → The Array I want returned
end
As someone downvoted this answer here is the full working code:
This get an Array field from a Firestone database and then returns a list dynamic.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
class GetUserLikes {
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
final user = FirebaseAuth.instance.currentUser!;
Future<List> getUsersLikes() async {
// Get the list of user likes from the Firestone Database and then
// return the list so it will only show the users likes on the profile page.
try {
final docRef = _firestore.collection("user_details").doc(user.uid);
DocumentSnapshot doc = await docRef.get(); // Await
final data = doc.data() as Map<String, dynamic>;
return data['user_likes'];
} catch (err) {
print('There was an error');
}
return ['Nothing Returned'];
}
Future<List> getLikes() async {
// Takes the Future<List> and turns it into a List<dynamic>
Future<List> userLikes = getUsersLikes();
List list = await userLikes;
return list; // Returns List<dynamic>
}
}
Then on the receiving Future builder it will have to be awaited.
GetUserLikes userLikesList = GetUserLikes();
List userLikes = await userLikesList.getLikes();

How to cast dynamic to T or List<T>

I have a service to call api and some methods expects just Object and the rest expects list of objects. And I'm trying some tricks with generics but then errors in _get method with casting occurs.
// List
Future<List<ToDo>> getToDos() async {
final List<Map<String, dynamic>> response =
await _get<List<Map<String, dynamic>>>(url: "ToDos");
final List<ToDo> result =
response.map((data) => ToDo.fromJson(data)).toList();
return result;
//Object
Future<ToDo> getToDo() async {
final Map<String, dynamic> response =
await _get<Map<String, dynamic>>(url: "ToDo");
final ToDo result = ToDo.fromJson(response);
return result;
}
Future<T> _get<T>({
required String url,
}) async {
final Response response = await get(
Uri.https(_apiURL, url),
);
if (response.statusCode == 200) {
final T jsonResponse = json.decode(response.body) as T;
return jsonResponse;
} else {
throw Exception(response.body);
}
}
Error:
Exception has occurred. _CastError (type 'List<dynamic>' is not a subtype of type 'List<Map<String, dynamic>>' in type cast)
Is it even possible to solve it like I'm trying?
[Update]:
Solution:
Future<T> _get<T, K>({
required String url,
}) async {
final Response response = await get(
Uri.https(_apiURL, url),
);
if (response.statusCode == 200) {
final dynamic jsonResponse = json.decode(response.body);
if (jsonResponse is List) {
return List<K>.from(jsonResponse) as T;
} else {
return jsonResponse as T;
}
} else {
throw Exception(response.body);
}
}
There's a list function called cast. You can cast a dynamic list to List<Map<String, dynamic>> like this:
final aList=[]//your list;
final castedList=aList.cast<Map<String, dynamic>>();

PlatformException error, Invalid document reference, When attempting to work with Firebase Storage

I have created a function to work on my app. This function add's the photo from my camera or gallery into the Firebase storage, and into the user collection. Althought I'm receiving a strange error when trying to add the data. I have attempted to pass throught this Exception but the data wasn't added neither.
The erro:
This is the function:
class Product {
final Firestore firestore = Firestore.instance;
final FirebaseStorage storage = FirebaseStorage.instance;
DocumentReference get firestoreRef => firestore.document('products/$id');
StorageReference get storageRef => storage.ref().child('products').child(id);
Future<void> save() async {
loading = true;
final Map<String, dynamic> data = {
'name': name,
'description': description,
'sizes': exportSizeList()
};
if (id == null) {
final doc = await firestore.collection('products').add(data);
id = doc.documentID;
} else {
await firestoreRef.updateData(data);
}
final List<String> updateImages = [];
for (final newImage in newImages!) {
if (images.contains(newImage)) {
updateImages.add(newImage as String);
} else {
final StorageUploadTask task =
storageRef.child(Uuid().v1()).putFile(newImage as File);
final StorageTaskSnapshot snapshot = await task.onComplete;
final String url = await snapshot.ref.getDownloadURL() as String;
updateImages.add(url);
}
}
for (final image in images) {
if (!newImages!.contains(image)) {
try {
final ref = await storage.getReferenceFromUrl(image);
await ref.delete();
} catch (e) {
debugPrint('Falha ao deletar $image');
}
}
}
await firestoreRef.updateData({'images': updateImages});
images = updateImages;
loading = false;
}
}
From the error message is looks like id doesn't have a value in this call:
firestore.document('products/$id');
When id has no value, that leads to a document reference with a path /products/, which explains the error message.
So you'll want to run the code in a debugger, set a breakpoint on that line, and figure out why id doesn't have a value at that point.

Flutter: Cannot store Firestore data to local variable (returns null)

I have an issue when trying to store data from Firestore to a local variable.
class AppUser {
String _userId;
Map<String, dynamic> _userData;
Future getUserDataFromDb() async {
_userData = await dbInterface.getFinancialsFromDB(_userId);
// dbInterface.getFinancialsFromDB(_userId).then((Map<String, dynamic> data) {
// _userData = data;
// });
print(_userData); // flutter: null
}
}
_userData always returns null.
class Db {
CollectionReference financials = FirebaseFirestore.instance.collection('financials');
Future<Map<String, dynamic>> getFinancialsFromDB(userId) async {
financials.doc(userId).get().then((DocumentSnapshot documentSnapshot) {
if (documentSnapshot.exists) {
print(documentSnapshot.data()); // flutter: {'key1': 'data1', ...}
return documentSnapshot.data();
}
});
return null;
}
}
Db dbInterface = Db();
Within the "getFinancialsFromDB"-Function it prints the correct Map. So the issue isn't to retrieve the data from Firestore but to store it in the _userData variable.
The getUserDataFromDb() is called in an initState.
Any ideas what I could do to fix this issue? If you need any additional infos please let me know.
Thanks a lot, I really appreciate any help.
All the best,
Alex
When writing code an in async function, don't use then. Instead, use await to get the result of a Future.
Future<Map<String, dynamic>> getFinancialsFromDB(userId) async {
var documentSnapshot = await financials.doc(userId).get();
if (documentSnapshot.exists) {
return documentSnapshot.data();
}
else {
return null;
}
}

Getting this error - type 'Future<dynamic>' is not a subtype of type 'List<dynamic>'

Whenever trying to call future data and trying converting to List, it returns the error
type 'Future' is not a subtype of type 'List'
Tried type-casting, but no help
On HomePage.dart
final getPost = NetworkFile().getPosts();
List posts;
void getPostsList() {
setState(() {
var res = getPost;
posts = res as List<dynamic>;
print(posts);
});
}
On Network.dart
class NetworkFile{
Future<dynamic> getPosts() async {
var response = await http.get('$kBlogURL' + 'posts?_embed');
Iterable resBody = await jsonDecode(response.body.toString());
return resBody;
}
}
You are decoding the response and its a List of type dynamic. There are few method to handle it. You can create a simple PODO class and cast/mapped to it. Or just do like below:
List posts = [];
void getPostsList() async {
final fetchedPosts = await NetworkFile().getPosts();
setState(() {
posts = fetchedPosts;
});
print(posts);
}
Here is a nice article about PODO.
final getPost = NetworkFile().getPosts();
Map posts;
void getPostsList() async {
var res = await getPost;
setState(() {
posts = res as Map<String, dynamic>;
print(posts);
});
}
class NetworkFile {
Future<dynamic> getPosts() async {
var response = await http.get('https://onetechstop.net/wp-json/wp/v2');
var resBody = await jsonDecode(response.body.toString());
return resBody;
}
}