I want to convert realtime database to cloud firestore - firebase

Below is the code that I need to convert
DatabaseReference driversRef =
FirebaseDatabase.instance.reference().child("drivers");
driversRef
.child(currentfirebaseUser!.uid)
.once()
.then((DataSnapshot dataSnapShot) {
if (dataSnapShot.value != null) {
driversInformation = Drivers.fromSnapshot(dataSnapShot);
}
})
I have set up cloud store but I can't seem to get the code write to translate what I have to firestore.
This is my try
:
driversRef
.doc(currentfirebaseUser!.uid)
.collection('earnings')
.get()
.then((value) {
if (value != null) {
driversInformation = value.toString();
}
});
below is a picture of database structure

I think you are using collection('earning) after the Doc is wrong. because you can use it in starting & once just like table name.
you can try this
final databaseReference = FirebaseFirestore.instance;
databaseReference.collection('drivers').doc(currentfirebaseUser!.uid).snapshots().listen((event) {
//If you want to listen like streaming
evenyt.data(); //<- access data in <String,dynamic>
}
// If you want to list only once
var response = await databaseReference.collection('drivers').doc(currentfirebaseUser!.uid).get();
response.data()?['earning'] ?? 0 // access specific key value
here I show you my example similar to you:
I am updating notification badge values when it will change.
here is my cloud firestore structure.
//If you want to listen only once
Future<int> getBadgeCount({required String uid}) async {
var response = await databaseReference.collection('Badges').doc(uid).get();
return (response.data() != null) ? (response.data()?['BadgeCount'] ?? 0) : 0;
}
//If you want to listen like streaming
databaseReference.collection('Badges').where(uid).limit(1).snapshots().listen((response) {
badgeCount = response.docs.isNotEmpty ? (response.docs.first.data()['BadgeCount'] ?? 0) : 0;
printLog(message: "BadgeCount: ", variable: badgeCount);
});
}

Related

How to passing final List<File> keepImage = [] to next page

How to passing the list of image to next page i try to declare at the top of code and do like this but it said
PostView({File? keepImage}) : this.keepImage = keepImage ?? [];
'keepImage' isn't a field in the enclosing class.
Try correcting the name to match an existing field, or defining a field named
i have keep image into
final List<File> keepImage = [];
and here is pick image function
Future<void> chooseImage() async {
final pickedFile = await picker.getImage(source: ImageSource.gallery);
setState(() {
keepImage.add(File(pickedFile!.path));
});
if (pickedFile?.path == null) retrieveLostData();
}
Future<void> retrieveLostData() async {
final LostData response = await picker.getLostData();
if (response.isEmpty) {
return;
}
if (response.file != null) {
setState(() {
keepImage.add(File(response.file!.path));
});
} else {
print(response.file);
}
}
There are several ways you can do this.
The easiest is using shared preferences to store the image url in cache and so you can retrieve it wherever you want. Another is using arguments, when navigating to the other page, pass the id of this image for it.

Flutter Firebase async query not retrieving data inside a stream function

I am trying to query a User from firebase within another query but for some reason but I can't get the code to work
The function the wont run is await usersRef.doc(uid).get(); and can be found here:
static getUserData(String uid) async {
return await usersRef.doc(uid).get();
}
static DirectMessageListModel getDocData(QueryDocumentSnapshot qdoc, String uid) {
Userdata postUser = Userdata.fromDoc(getUserData(uid));
return DirectMessageListModel.fromDoc(qdoc, postUser);
}
static DirectMessageListModel fromDoc(QueryDocumentSnapshot doc, Userdata altUser) {
return DirectMessageListModel(
doc['chatId'],
doc['lastMsgContent'],
doc['lastMsgType'],
altUser
);
}
parent function:
Stream<List<DirectMessageListModel>> getMeassageList(){
var snaps = FirebaseFirestore.instance.collection('directMessages').where('users', arrayContains: userdata!.uid).snapshots();
List<String> usersListElement = [];
return snaps.map((event) { return event.docs.map((e) {
usersListElement = [e.get('users')[0], e.get('users')[1]];
usersListElement.remove(userdata!.uid);
return DirectMessageListModel.getDocData(e, usersListElement.first);
}).toList();
});
}
You forgot to wait for the future getUserData(uid) to complete.
Try this:
static Future<DocumentSnapshot<Object>> getUserData(String uid) async {
return await usersRef.doc(uid).get();
}
static DirectMessageListModel getDocData(
QueryDocumentSnapshot qdoc,
String uid,
) async {
Userdata postUser = Userdata.fromDoc(await getUserData(uid)); // await here
return DirectMessageListModel.fromDoc(qdoc, postUser);
}
..
// parent function.
// Also wait for the future in the parent function.
// UPDATE BELOW! Define the parent function like this:
Stream<List<Future<DirectMessageListModel>>> getMeassageList() {
var snaps = FirebaseFirestore.instance
.collection('directMessages')
.where('users', arrayContains: userdata!.uid)
.snapshots();
List<String> usersListElement = [];
return snaps.map((event) {
return event.docs.map((e) async {
usersListElement = [e.get('users')[0], e.get('users')[1]];
usersListElement.remove(userdata!.uid);
return await DirectMessageListModel.getDocData(e, usersListElement.first);
}).toList();
});
}
NB: You are fetching user data (either sender/receiver) for each message in directMessages collection. It might be better to store just sender/receiver name in directMessages collection and simply display that. Then if the user clicks on a message, you can then fetch the full sender/receiver data.

How to modify Flutter Firebase Stream listener based on Firebase Auth stream when using Provider for DI?

In my Flutter Firebase App with Provider for state management, I have a stream for reacting to FirebaseAuth.instance.authStateChanges() and a separate stream for listening to the my app related metadata for the logged in uid provided by FirebaseAuth.
return MultiProvider(
providers: [
// This returns a stream of firebase user auth events so my app can react to
// login, force logout, etc.
StreamProvider<fireauth.User>.value(
value: FirebaseAuth.instance.authStateChanges(),
),
// conditional on non-null FirebaseAuth User, I would like to register a Firestore listener
// for the provided userId.
// For security purposes, if the authenticated uid changes, the listener should be dereigstered.
// After logout, if a different user is logged in, the this stream should listen to that uid's doc.
StreamProvider<MyUser>.value(
value: FirebaseFirestore.instance.collection('users')
.doc(/* use the userId from firebaseAuth here! */)
.snapshots()
.map((ds) => MyUser.fromJson(ds.data()))
),
],
);
I think I can use ProxyProvider to allow the MyUser stream to take a dependency on the FirebaseAuth.User stream, but once the MyUser stream is registered for this uid, it seems to be immutable. How can I "reload" the Firestore stream based on the result from the FirebaseAuth.User?
Ran into the same problem but with Firebase Realtime Database. Using the async package I created a StreamGroup. A StreamGroup.
Create StreamGroup:
StreamGroup group = StreamGroup();
Create a stream Variable:
Stream streamvar;
created function with this scheme:
Stream<PlaceHolderClass> functionName(User user) async*{
if (user != null) {
await for (var x in streamOfFirestoreDocuments) {
yield PlaceHolderClass();
}
} else {
yield PlaceHolderClass();
}
}
Created an initializer:
where I listened to:
FirebaseAuth.instance.authStateChanges()
and added it to group by group.add(),
also set the stream variable and added it to the group:
streamvar = functionName(FirebaseAuth.instance.currentUser);
group.add(streamvar)
then created:
Stream<FirestoreDocuments> providerFunc(){
return group.stream.map((event) {
if(isUserChangetest){
group.remove(streamvar);
streamvar = newStreamvar;
group.add(newStreamvar)
fetch = newFirestoreDocs;
return fetch;
}else{
return sth;
}
})
}
Now streamVar always holds a reference to the last firestore stream input to group.
Swap stream from Firestore and you can listen to both kind of changes Firestore and Auth.
Incase I missed something:
class Wallet {
static final Wallet _singleton = Wallet._internal();
factory Wallet() {
return _singleton;
}
Wallet._internal();
Stream coins;
create() {
Stream<CrossOver> signin = FirebaseAuth.instance
.authStateChanges()
.map((event) => CrossOver(user: event, isnum: false));
group.add(signin);
coins = replace(FirebaseAuth.instance.currentUser);
group.add(coins);
}
Stream<CrossOver> replace(User user) async* {
if (user != null) {
await for (var x in FirebaseDatabase.instance
.reference()
.child('users/' + user.uid + '/scans')
.onValue) {
yield CrossOver(coins: Coins.load(x.snapshot.value), isnum: true);
}
} else {
yield CrossOver(coins: Coins.load(0), isnum: true);
}
}
Stream<Coins> real() {
return group.stream.map((event) {
Coins val;
if (event.isnum == true) {
print('new money');
val = event.coins;
}
if (event.isnum == false) {
Stream<CrossOver> nStream = replace(event.user);
print('new user');
group.remove(coins);
coins = nStream;
group.add(nStream);
FirebaseDatabase.instance
.reference()
.child('users/' + event.user.uid + '/scans')
.once()
.then((value) => val = Coins.load(value.value));
}
return val;
});
}
StreamGroup<CrossOver> group = StreamGroup();
}
class Coins {
int money;
Coins(this.money);
factory Coins.load(int i) {
return Coins(i);
}
}
class CrossOver {
bool isnum;
User user;
Coins coins;
CrossOver({this.user, this.coins, this.isnum});
}
I used flatMap() in rxdart to merge and combine the auth user stream and the firestore user stream so the resulting stream listens to both auth and firestore changes.
I wrote a more detailed answer with the code here: https://stackoverflow.com/a/66234728/10394353

How to check if firestore database document exist when given a document id?

I want to check if a document in firestore exist when given a document id. So far I have tried this:
String getUserType(String uid) {
final result = Firestore.instance.collection('patients').document(uid).get();
if (result == null) {
return 'null';
} else {
return 'exist';
}
you can use result.exists.
original post: https://stackoverflow.com/a/56465899/4465386
final result = await Firestore.instance
.collection('posts')
.document(docId)
.get()
if (result == null || !result.exists) {
// Document with id == docId doesn't exist.
}

Flutter Firestore query with startAfter

I am using Flutter (cloud_firestore) and trying to get data from Firestore after document with title 'xxx', but it returns 0 results.
return Firestore.instance.collection('products')
.orderBy('title')
.startAfter([{'title': 'xxx'}
]);
What am I doing wrong? How can I properly implement flutter pagination?
You should pass a value, not a map:
return Firestore.instance.collection('products')
.orderBy('title')
.startAfter(['xxx']);
The documentation on this is not particularly clear.
This is what worked for me. My orderBy is based on {FirstName, LastName & Email}. So, the startAfter should also match these field values. I saved the document in a variable and later made a list with the values of those fields and used as startAfter parameter.
static final Query queryBase = userCollectionRef
.orderBy(FieldNames.FIRST_NAME)
.orderBy(FieldNames.LAST_NAME)
.orderBy(FieldNames.EMAIL);
DocumentSnapshot _lastUser;
Future<List<DocumentSnapshot>> getAllUserDocuments({
bool next,
int limit = 10,
}) async {
List<DocumentSnapshot> _userDocSnaps = [];
try {
if (!next) _lastUser = null;
Query _query = queryBase;
if (_lastUser != null)
_query = _query.startAfter([
_lastUser.data[FieldNames.FIRST_NAME],
_lastUser.data[FieldNames.LAST_NAME],
_lastUser.data[FieldNames.EMAIL],
]);
var _userDocsSnap = await _query.limit(limit).getDocuments();
if (_userDocsSnap != null && _userDocsSnap.documents != null) {
_userDocSnaps = _userDocsSnap.documents;
if (_userDocSnaps != null && _userDocSnaps.length >= 1)
_lastUser = _userDocSnaps[_userDocSnaps.length - 1];
}
} catch (err) {
String errMessage = 'Exception in method _getAllUserDocuments';
PrintHelper.handlePrint(errMessage, err);
}
return _userDocSnaps;
}
You can pass entire doc using startAfterDocument method
_db
.collection('requirement')
.orderBy('createdAt', descending: true)
.startAfterDocument(lastVisible)

Resources