Flutter - Render widgets based on Cloud Firestore data [closed] - firebase

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I have a flutter ecommerce grocery app and I have some trouble in backend.
I have a products screen that has addtoCart function that adds that item to Cloud firestore as follows
Future<void> _addToCart(final uid,
String title,
String price,
int unit,
int total,) {
CollectionReference cart = FirebaseFirestore.instance.collection(
'users/$uid/cart');
return cart
.doc(title)
.set({
'title': title,
'price': price,
'unit': unit,
'total': total,
'order_status': 'in_cart',
'order_placed_time': DateTime.now(),
});
}
This places products that have been added to cart as follows
cloud firestore image
Now the problem I am having it to take these products that I have added to firestore and render them in my carts screen which is subject to changes as user constantly adds them. How can I render them should I used SharedPrefs?

A quick solution would be the usage of StreamBuilder<T> which is able to listen for changes on Firestore and update your UI in in realtime.
// Define this somewhere
final firestoreStream = Firestore
.instance
.collection('abc')
.snapshots();
// Then in the 'build' method
StreamBuilder<QuerySnapshot>(
stream: firestoreStream,
builder: (context, snapshot) {
if (snapshot.hasData) {
return const SomeWidget();
}
if (snapshot.hasError) {
return const ErrorWidget();
}
return const Center(
child: CircularProgressIndicator(),
);
},
);
While this is quick to implement, you'd better use a state management solution such as Bloc or Riverpod (or anything else).
In particular, the stream would be handled by the state management library internally which will rebuild the UI accordingly. In this way, you can also avoid undesired rebuilds, implement caching, filtering and much more.
Please note that I am not talking about performance because StreamBuilder<T> is very good. Instead, I'm saying that a state management library should take care of the stream for a better separation of concerns (which keeps the code easier to maintain).

I would recommend looking into using a StreamBuilder example this basically allows your app to listen to a collection in firebase and rebuild widgets whenever there is a change. This way you will never have to manually trigger a rebuild whenever a document in Firestore is created, updated, or deleted.

Related

How to update a list automatically using Firestore Stream?

In my app, I am now using a "refresh function" to update a list in Provider. When the user swipe, I call Refreshlist in my provider and with NotifyListeners() it updates my UI just fine. (The UI is linked to the list _myEleves).
I am afraid that users might use this "refresh" button too many times making unnecessary calls and "reads" on firebase and so increasing artificially the number of reads so the costs of Firebase.
Here is the code :
Future<void> refreshEleveList() async {
final DocumentSnapshot<Map<String, dynamic>> docInfo =
await FirebaseFirestore.instance
.collection('familyAccounts')
.doc(_accountEmail.toLowerCase())
.get();
_mesEleves = (docInfo['mesEleves'] as List<dynamic>)
.map((data) => Eleve.fromMap(data))
.toList();
notifyListeners();
}
I have been reading about STREAMS a lot, but I just can't get it right on how to start this stream, the listening to the changes on Firebase inside my PROVIDER file, so that changes will be made to "_myEleves" list.
What I want to do is that each time a change on firebase happens, it updates my list "_myEleves". Is there a simple way to do this ?
My Provider covers the whole app (I use it in the MAIN file). I thought of adding a StreamProvider, but the thing is I don't want this stream to start until user is authentified etc... and userInfo is first downloaded.
Right now : when user logs in : it downloads from firebase all necessary info, _mesEleves being one of them (This is for a teacher). Whenever a new student joins the group, it modifies firebase and so it should stream down this info into "myEleves" list on the teacher account.
Anybody can help ?

Firebase: avoiding READs when updating data

I am currently setting up my 1st Firebase store and wondering how to best avoid unnecessary read/write costs (as well as how to create a nested structure...). Quite helpful was this answer.
However, if I listen to changes (caused by other persons) of a document, I assume I also get any change of myself again in return. So when using the logic of the todo example for bloc, I update a document. My listener recognizes this and fires an event to re-read the data from the repository.
#override
Stream<TodosState> mapEventToState(TodosEvent event) async* {
if (event is LoadTodos) {
yield* _mapLoadTodosToState();
} else if (event is TodosUpdated) {
yield* _mapTodosUpdateToState(event);
} else if (event is UpdateTodo) {
yield* _mapUpdateTodoToState(event);
}
Stream<TodosState> _mapLoadTodosToState() async* {
_todosSubscription?.cancel();
_todosSubscription = _todosRepository.todos().listen(
(todos) => add(TodosUpdated(todos)),
);
}
Stream<TodosState> _mapTodosUpdateToState(TodosUpdated event) async* {
yield TodosLoaded(event.todos);
}
Stream<TodosState> _mapUpdateTodoToState(UpdateTodo event) async* {
_todosRepository.updateTodo(event.updatedTodo);
}
Since I assume there may be multiple near time changes to a document by the same user in my app, is setting the source option to offline cache for 1min with each write access a proper option or are there better options?
And in case there isn't, can I somehow ensure that the data is sent when the user leaves the app (eg. when bringing another app upfront)?
And is there any overview how to use Firestone with Flutter? Unfortunately the coding examples in Google's documentation are for any language but Dart/Flutter. How would I, for example, set the source option with Flutter (haven't searched for it yet)?
You really can't have it both ways, you would either need to give up realtime or assume that this could generate more costs and as mentioned by #creativecreatorormaybenot you should still be using Listeners to deal with realtime updates.
The comments made in the accepted answer you shared are valid points to take better advantage of listeners with the use of cache and specially pagination, as you are very likely not required to have all of your documents in memory all the time.
Also, listeners are rather unexpensive for small projects, as you appears to be, and you have a free tier of 50.000 reads a day for Firestore, which will include read that come from listeners.

Read data from Firebase created by loggedin user - Flutter [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I've seen a lot of examples online on how to write and read data to Firebase. However, I want to know how to write and read data from Firebase only created by logged in User.
How do we bind such data to a user?
Thanks
It might depend on how your data are oranized. Read through this:
https://firebase.google.com/docs/firestore/manage-data/structure-data
A simple example:
// snippet for pulling from data once it is there
await FirebaseFirestore.instance
.collection("USERDATA")
.doc(userID)
.collection('DOCUMENTS')
.get()
// one way you might supply the function that puts data up to firestore.
uploadToCloudStorage(
userID: user.fAuthUser.uid, fileToUpload: File(filePath));
Use the userId to as the docId for the documents in firebase. Here is an example.
createOrUpdateUserData(Map<String, dynamic> userDataMap) async {
FirebaseUser user = await FirebaseAuth.instance.currentUser();
DocumentReference ref =
Firestore.instance.collection('user').document(user.uid);
return ref.setData(userDataMap, merge: true);}

Flutter and Firebase: Return all images from Firebase Storage

I have seen a few articles written online by people pertaining to be able to do this, but they only tell you how to do this with a specific, controlled list of images where they also know all the filenames beforehand.
There is also this "answer" posted here: Flutter - Get all images from firebase storage which does not actually resolve this issue at all as it suggests a .listAll() method for the recommended plugin, but there is no such method as .listAll() using the suggested plugin.
I need to be able to not know how many images are in Firebase storage, or what they might be called, just to return everything stored there.
UPDATE:
So because Firebase is full of so many limitations that it hardly qualifies as a database at all, it seems we may have to keep the images in Firebase Storage and a reference list of these in a Firebase Realtime Database Document.
I am stuck on the actual implementation of this however, as I am not even sure firstly how best to go about this. What I am attempting to do is store all the Storage image URLs in an array (if this is not the best way to do this, let me know!):
Firebase Structure
collection -> document -> fields
userData profileImages URLs (array)
My first issue is that I don't know how to append new data to the existing array, it seems to just overwrite it each time I add a new item so that I only ever have one string in the array in the database:
Firestore.instance.collection('userData').document('profileImages').updateData({
'URLs': _uploadedFileURL,
});
Then after this I am also not sure how to actually retrieve the full array of data later when I need it:
Container(
child: StreamBuilder(
stream: Firestore.instance.collection('userData').document('profileImages').snapshots(),
builder: (BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (!snapshot.hasData) {
return LoadingAnimationBasic();
}
if (snapshot.data.data == null) {
return LoadingAnimationBasic();
} else {
return ListView(
shrinkWrap: true,
children: _buildProfileGallery(snapshot),
);
}
},
),
),
And then the function:
_buildProfileGallery(AsyncSnapshot<DocumentSnapshot> snapshot) {
int test = snapshot.data["URLs"].length;
print('URLs in List: ' + test.toString());
return snapshot.data.data.map(???);
}
I have no idea what to put as the parameters of this map, as the hint text is insane:
MapEntry(K2, V2> f(String key, V value)
I can't even begin to guess what this means.
Am I on the right track? Am I on the right planet?
The ability to list files was added to Firebase's client-side SDKs for Android, iOS and JavaScript last year, but has not yet landed in the FlutterFire bindings.
The answer to the question you linked, refers to a pull request on the FlutterFire open-source project that adds this functionality. So while somebody wrote code to allow listing of files in Flutter too, this code hasn't been added to a release so far. So the only way to use that code now, is to build your own version of the FlutterFire library for firebase_storage.
Without the ability to list files in the Firebase Storage API, you'll have to revert back to what everyone did before this feature was added: keeping a list of the files in a secondary location, such as the Firebase Realtime Database or Cloud Firestore.

Deal with huge amount of data in Firestore in flutter project

Normally, we use StreamProvider to deal with the data from FireStore in Flutter project like this:
// I have a collection of Customer in my DataService
Stream<List<Client>> streamCustomers() {
return Firestore.instance.collection('customers').snapshots().map((list) =>
list.documents.map((doc) => Customer.fromMap(doc.data, doc.documentID)).toList());
}
This is the Provider of stream data:
Expanded(
child: StreamProvider<List<Customer>>.value(
value: _dataSvc.streamCustomers(),
child: CustomerListWidget(),
),
);
This is where the stream data consumed:
final _customers = Provider.of<List<Customer>>(context);
return Container(
child: _customers == null? Text('Loading...') : _buildList(context, _customers),
);
I'll show all the customer data in CustomerListWidget. Because the data of Customer collection is very big (more the 10,000 - 50,000 records). Apparently this is not efficient solution. I'm wondering normally what kind of the practical solutions are used to deal with this scenario in Flutter/Firestore project?
P.S.: Pagination is definitely one of my possible choice. But there are some issues because I'll apply some filters to the data. For example, I have to query to Firestore every time when the filter criterio has been changed which will cause the data usage increased. And also it seems I can only use getDocuments() instead of snapshot to get the Stream data.
I think using Pagination is which better fits for you. Implementing pagination in Flutter using Firebase Cloud Firestore database can improve your app performance and reduce bandwidth usage (which is one of your biggest concerns). There are some articles about this.

Resources