I was following this tutorial on how to get realtime updates from flutter firestore, https://medium.com/firebase-tips-tricks/how-to-use-cloud-firestore-in-flutter-9ea80593ca40 and I scrolled down to Listen For Realtime Updates section and when I followed the tutorial, this is what I came up with,
String name = 'name here';
String children = 'children here';
String docId = '0';
#override
void initState() {
getUsers();
super.initState();
}
getUsers() async {
final FirebaseAuth auth = FirebaseAuth.instance;
final User? user = auth.currentUser;
final uid = user!.uid;
FirebaseFirestore.instance
.collection("userNames")
.where("uid", isEqualTo: uid)
.snapshots()
.listen((result) {
result.docs.forEach((result) {
print(result["firstName"]);
print(result["children"].toString());
name = result["firstName"];
children = result["children"].toString();
});
});
}
When I print the values to the console they update in realtime, but when I put them in variables and concatenate them into a Text widget like this:
Text('Children: $children'), //It does not update in realtime.
For instance, if in my document if I have children: 3 and I display in in my app, it shows 3, but when I manually change it, it does not update in realtime, I have to press hot reload. Another issue is that I have to initialize the variable before using them in the function, up ahead in the first 3 lines of code. When I hot restart, it shows the values of what I use to initialize them. For where it should show children, it says 'children here' and for where the name is, it puts 'name here', only when I hot reload the page, do the actual firestore values get inputed into them and show data from the firestore database. If there is a solution to any of these problems, I would much prefer an answer in code instead of a link or a brief explanation, I spend hours before I find a piece of code that utilizes the explanation. Thank you
I use snapshots().listen() to listen to change. Then I use ValueNotifier to notify the UI.
final itemsNotifier = ValueNotifier<List<Item>>([]);
FirebaseFirestore.instance
.collection("userNames")
.where("uid", isEqualTo: uid)
.snapshots()
.listen((event) {
itemsNotifier.value = event.docs
.map((doc) => Item.fromSnapshot(
doc as DocumentSnapshot<Map<String, dynamic>>))
.toList();
itemsNotifier.notifyListeners();
});
Since the data is loaded asynchronously, the data isn't available when Flutter first paints your Text widget. You'll need to tell Flutter that it has to repaint the UI when the data is available.
There are two common ways to do this:
Put the children variable in the state of your widget by calling setState(). This will tell Flutter to repaint the widget, and your text will then show the value.
You can also use a StreamBuilder widget, which does the above too - but it also handles all kinds of error states automatically.
I recommend reading about stateful widgets and setState and about the StreamBuilder class to learn more.
Related
In my firestore I have a list of documents which represent locations on a map.
I would like to show a local notification not only when a new document is created in the database, but also when the location is within a certain distance from my current location.
At the moment I have a streambuilder which loads the position into my local map, and a streamlistener to give a notification on a new document:
CollectionReference loc =
FirebaseFirestore.instance.collection('locations');
late Stream<QuerySnapshot> _locStream;
late StreamSubscription<QuerySnapshot> streamSub;
#override
void initState() {
super.initState();
_locStream = loc.snapshots();
streamSub = _locStream.listen((data) {
final snackBar = SnackBar(
content:
Text('New location added!'));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
});
}
the problem is that the stream is returning ALL the documents, not only the new one, so I have no idea how to "isolate" the new one and, more important, how to get its value in order to compare it with my current location.
Is that possible to achieve so?
A Firestore QuerySnapshot always contains all information that fits within the query. But when the QuerySnapshot is an update on an existing listener/stream, it also contains metadata about what changes compared to the previous QuerySnapshot on the listener/stream.
To get access to this metadata, use the QuerySnapshot's docChanges property, rather than docs, and check the DocumentChangeType of the type property of each change to find only the documents that were added. In the initial snapshot that will be all of the documents, since all of them are new to the snapshot at that point.
See the Firebase documentation on viewing changes between snapshots
I want to show in my code as Text the length of the document from a specific collection like this one.
I want to show in Flutter how many document inside "Agung"
this is the ss of my Firebase
I think this question has been answered here
to show how many documents you have inside Agung you can use :
int countDocuments() async {
QuerySnapshot _myDoc = await Firestore.instance.collection('Agung').getDocuments();
List<DocumentSnapshot> _myDocCount = _myDoc.documents;
return _myDocCount.length; // Count of Documents in Collection
}
Then you can just call the function and put the result on your Text Widget
I want to check if a certain id in a collection.document.collection.document() is available in firebase flutter dart, if it is so I remove the id else I add that id in the database.
So my problem is accessing the id value, I have tried .contains method but was always returning false even if the value is present. How can I work around this
this my firestore design
Firestore.instance
.collection('postt')
.document(postsId)
.collection('type')
.document();
I don't know what is your firestore design look like but according to your description this example should work.
DocumentSnapshot doc = await FirebaseFirestore.instance.collection('posst')
.doc('postsId')
.collection('type')
.where('id',isEqualTo: 'your id')
.get();
if(doc.exists){
// todo
}else{
// todo
}
I have a futter app and want to add items favorite by the user in a separate collection "userFavorites" which will store all favorite items depending on the current user uid by doing so:
Future getCurrentUser() async {
final FirebaseUser user = await FirebaseAuth.instance.currentUser();
final uid = user.uid;
return uid.toString();
}
Future<void> toggleFavoriteStatus() async{
var userId = await getCurrentUser();
final oldStatus = isFavorite;
isFavorite = !isFavorite;
notifyListeners();
try{
await Firestore.instance.collection("userFavorites/$userId").document(id).updateData({
'isFavorite': isFavorite,
});
}catch(error){
_setFavValue(oldStatus);
}
}
But I receive this error when I try to favorite any item:
Invalid document reference. Document references must have an even number of segments, but userFavorites/FRbYxmNpSBcda6XOrQUjukvFvVb2/q7eLxtZfhG3g6Pd1bYY4 has 3
E/MethodChannel#plugins.flutter.io/cloud_firestore(14551): at com.google.firebase.firestore.DocumentReference.forPath(com.google.firebase:firebase-firestore##21.3.0:80)
The error message:
Invalid document reference. Document references must have an even number of segments, but userFavorites/FRbYxmNpSBcda6XOrQUjukvFvVb2/q7eLxtZfhG3g6Pd1bYY4 has 3
is telling you that you built a path to a document:
userFavorites/FRbYxmNpSBcda6XOrQUjukvFvVb2/q7eLxtZfhG3g6Pd1bYY4
which doesn't look like a document at all, since it has three path segments:
userFavorites
FRbYxmNpSBcda6XOrQUjukvFvVb2
q7eLxtZfhG3g6Pd1bYY4
This is the line of code that built your path:
Firestore.instance.collection("userFavorites/$userId").document(id)
Since we can't see your data, it's hard to tell what you actually meant to do here. But in any event, Firestore is taking "userFavorites" to be the name of a top level collection, "FRbYxmNpSBcda6XOrQUjukvFvVb2" is the name of a document in that collection, and "q7eLxtZfhG3g6Pd1bYY4" is taken to mean a subcollection under that document. If you meant something else, you'll have to figure out how to build the path to that document to query it.
I ran into this problem using a doc reference & instead of using [document_reference].path I accessed it using the ID: [document_reference].id
and that solved it for me.
hi i am trying to increment a value when clicked the button if data is available in firestore this is my code bloc if you have any suggestion lmk please
int q = 0;
final snapShot = await Firestore.instance.collection('cart').document("LIihBLtbfuJ8Dy640DPd").get();
if(snapShot.exists){
q=q+1;
}
Firestore.instance.runTransaction((Transaction transaction) async {
await transaction.update(
Firestore.instance
.collection("cart")
.document("LIihBLtbfuJ8Dy640DPd"),
{
foodItem.name: {
'itemName': foodItem.name,
'imgUrl': foodItem.imageAssetPath,
'itemPrice': foodItem.price,
'quantity': q,
}
});
});
In November 2021, this worked for me.
FirebaseFirestore.instance.collection('users').doc(currentUser?.id).update({
'bronzeBadges': FieldValue.increment(2),
});
var quantityref = db.collection("cart").document("LIihBLtbfuJ8Dy640DPd");
// Increment the quantity field by 1.
quantityref.update({
"quantity" : firebase.firestore.FieldValue.increment(1)});
If your want to change a value based on the previous one, you have basically two approaches:
Make use of transactions. I see you're doing that but incorrectly, because you're fetching the current value outside of it, and it could change by the moment you run the update, causing data inconsistencies. I don't know about Flutter, but as far as I know, a Transaction in Firebase consists in a read operation followed by one or more write operations, and the value returned from the read will be the very last one and won't be changed before you finish the transaction, so you can be sure you're working with the latest one. I suggest you to read the Transactions docs.
increment method (recommended): See this see this answer for incrementing in Flutter
First of all, you need to get the desired document and its elements to update the document of fields. In your example, it is quantity.
First, get the document:
Firestore.instance
.collection('cart')
.document('documentID')
.get()
.then((DocumentSnapshot ds) {
// use ds, parse ds then access the quantity
});
After doing the job, you need to update the field. Thankfully, there is an updateData function in firestore instance.
db.collection('cart')
.document('documentID')
.updateData({'quantity': someQuantity});
Hope it helps.