How to get name and phone number from realtime database in flutter? - flutter

I have one user in my database:
Users {
userId: Xx1j9Pih4BPnu01vnFdMfZqGOr02: {name: 'jack5' ,phone: '0845204281'
}
}
So far I have the following function for getting data from the realtime firebase database.
static Future<dynamic> getCurrentUserInfo() async {
String? userId = FirebaseAuth.instance.currentUser?.uid;
final ref = FirebaseDatabase.instance.ref();
final snapshot = await ref.child('users/$userId').get();
if (snapshot.exists) {
return snapshot.value;
} else {
print('No data available.');
return '';
}
The function returns an object. How do I convert this object into a string? Or: How do I simply get the name of the current user of my database?

static Future<dynamic> getCurrentUserInfo() async {
String? userId = FirebaseAuth.instance.currentUser?.uid;
final ref = FirebaseDatabase.instance.ref();
final snapshot = await ref.child('users/$userId').get();
if (snapshot.exists) {
Map<dynamic, dynamic> values = needsSnapshot.value;
values.forEach((key, values) {
print(values['name']);
print(values['phone']);
});
} else {
print('No data available.');
return '';
}
}

If you just want to get the name property of the user, assuming your users are stored by their UID, that'd be:
final snapshot = await ref.child('users/$userId/name').get();
print(snapshot.value);

Related

Make a stream wait for data to assign a late property

I have following code.
I need to assign a late userName (not stored in database BID table) from the Bid Object that i retreive from the firestore with a stream.
The userName can be found in another table in the database (USER table).
I need to connect those 2 all while a streambuilder is building with BID object stream coming in.
Repository
final _firestoreDB = FirebaseFirestore.instance;
Future<String> getDbUserNameFromDbUserID({required String dbUserID}) async {
try {
final docUser = _firestoreDB.collection('users').doc(dbUserID);
final snapshot = await docUser.get();
if (snapshot.exists) {
if (snapshot.data() != null){
return DbUser.fromJson(snapshot.data()!).userName;
}
}
throw Exception("getDBUserByDBUserId() No fireStore userName found");
} catch (e) {
throw Exception(e);
}
}
Stream<List<Bid>> getAllBidsByItemId({required String itemID}) {
try {
return _firestoreDB
.collection('bids')/*.orderBy('timestamp')*/
.where('itemID', isEqualTo: itemID)
.snapshots()
.map((snapshot) =>
snapshot.docs.map((doc) {
Bid bid = Bid.fromJson(doc.data());
bid.bidId = doc.id;
**bid.userName = await getDbUserNameFromDbUserID( dbUserID: bid.bidderID); ///????**
return bid;
}).toList());
} catch (e) {
throw Exception(e);
}
}
model
class Bid {
late String bidId;
**late String userName;**
final String bidderID;
final String itemID;
final double price;
final DateTime timestamp;
Bid(
{
required this.bidderID,
required this.itemID,
required this.price,
required this.timestamp});
Map<String, dynamic> toJson() => {
'bidderID': bidderID,
'itemID': itemID,
'price': price,
'timestamp': timestamp,
};
static Bid fromJson(Map<String, dynamic> json) => Bid(
bidderID: json['bidderID'],
itemID: json['itemID'],
price: json['price'],
timestamp: (json['timestamp'] as Timestamp).toDate(),
);
}
How can I assign the late String userName when the stream gets the objects from the firestore?
Whats the best practice to do this? I assume this is not the best way to go about it?
I am using Bloc and Firestore Firebase
Thank you
SOLUTION
Stream<List<Bid>> getAllBidsByItemId({required String itemID}) async* {
try {
yield* _firestoreDB
.collection('bids')
.where('itemID', isEqualTo: itemID)
.snapshots()
.asyncMap<List<Bid>>((event) async {
List<Bid> bids = [];
for (var doc in event.docs) {
try {
Bid bid = Bid.fromJson(doc.data());
bid.bidId = doc.id;
bid.userName = await getDbUserNameFromDbUserID( dbUserID: bid.bidderID);
bids.add(bid);
} catch (e) {
throw Exception(e);
}
}
return bids;
});
} catch (e) {
throw Exception(e);
}
}
This worked for me
SOLUTION
Stream<List<Bid>> getAllBidsByItemId({required String itemID}) async* {
try {
yield* _firestoreDB
.collection('bids')
.where('itemID', isEqualTo: itemID)
.snapshots()
.asyncMap<List<Bid>>((event) async {
List<Bid> bids = [];
for (var doc in event.docs) {
try {
Bid bid = Bid.fromJson(doc.data());
bid.bidId = doc.id;
bid.userName = await getDbUserNameFromDbUserID( dbUserID: bid.bidderID);
bids.add(bid);
} catch (e) {
throw Exception(e);
}
}
return bids;
});
} catch (e) {
throw Exception(e);
}}

Instance of 'Future<String?>' flutter

Why is returning Instance of 'Future<String?>' instead String value?
Future<String?> getUser() async {
User user = await FirebaseAuth.instance.currentUser!;
FirebaseFirestore firestore = await FirebaseFirestore.instance;
String uid = user.uid;
String? userName;
// to get username from firebase
return firestore
.collection("users")
.doc(uid)
.get()
.then((value) {
if (value.exists) {
var data = value.data();
userName = data?["name"];
print("There is data :$userName");
} else {
print("There no Data!");
}
return Future.value(userName);
});
}
I am trying to get String value?
The place you like to get data from this method use await & the method is needed to be async. like
_myFunction() async{
final value = await getUser();
Also I will suggest to not mixing await and .then.
Future<String?> getUser() async {
User user = FirebaseAuth.instance.currentUser!;
FirebaseFirestore firestore = FirebaseFirestore.instance;
String uid = user.uid;
String? userName;
// to get username from firebase
final value = await firestore.collection("users").doc(uid).get();
if (value.exists) {
var data = value.data();
userName = data?["name"];
print("There is data :$userName");
} else {
print("There no Data!");
}
return userName;
}

How to pass a List or specific looped list to firebase doc in flutter

I am trying to achieve a task in which I have a List<dynamic>and its giving me multiple values on its indexes e.g. ['Me','Admin', so on....] something like this.
I cannot pass the List directly to Document ID it gives index error and I don't if it will still give error or not If the List give data in string List<String>
I want to loop around the indexes of this list and pass it to Firebase collection's document id to get multiple data's of the users. For example on list's index 0 there's Me coming for myself and on index 1 there's Admin coming. Both have their respective data stored in Firestore collection with their own document id's Me and Admin. I want it to be checked on the runtime the app will check if its Me or Admin or Some other index value
Here's my code of the list and the firestore I'm trying to achieve.
List<dynamic> clientcodes = [];
void getclientcodes() async {
final clientcode = await FirebaseFirestore.instance
.collection("users")
.doc(FirebaseAuth.instance.currentUser!.email)
.get()
.then((clientcode) {
return clientcode.data()!["clientcode"];
});
setState(() {
if (clientcode != null) {
clientcodes = clientcode;
} else if (clientcode == null) {
setState(() {
const SpinKitSpinningLines(size: 100, color: Color(0xFF25315B));
});
}
});
}
Firestore:
Future getdatastatus() async {
DocumentSnapshot result = await FirebaseFirestore.instance
.collection("Statements")
// .doc("If I hardcode it the value of index 0 or 1 it works fine")
.doc(portfolionames.toString()) // This is area of issue
.get();
if (result.exists) {
print("Yes");
} else {
print("No");
}
}
You can insert getdatastatus() inside a loop, and let it get the index automatically by comparing it with any value you want it, see this:
Future getdatastatus() async {
for (var item in clientcodes) {
String docId = item.id;
if (docId == 'X' || docId == 'Y') {
DocumentSnapshot result = await FirebaseFirestore.instance
.collection("Statements")
.doc(docId)
.get();
if (result.exists) {
print("Yes");
} else {
print("No");
}
}
}
}
Hope that work with you!!
Update
In the first section of your code, I think there is a problem..
You can create the list out of the firestore streaming, then add the coming data to the list of model, after that you can loop it to take the value you want.
Class Database{
List<TestModel> clientcodes = [];
getclientcodes() {
return FirebaseFirestore.instance
.collection("users")
.doc(FirebaseAuth.instance.currentUser!.email)
.snapshots()
.listen((event) {
clientcodes.add(TestModel.fromMap(event));
setState(() {
if (clientcode != null) {
clientcodes = clientcode;
} else if (clientcode == null) {
setState(() {
const SpinKitSpinningLines(size: 100, color: Color(0xFF25315B));
});
}
});
});
}
}
class TestModel {
late String name;
late String description;
TestModel({
required this.name,
required this.description,
});
TestModel.fromMap(DocumentSnapshot data) {
name = data['name'];
description = data['description'];
}
}

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