Flutter Firestore create new Array every time function called - firebase

As per the question I'd like to add a new array every time I call my addPredection function for example I'd like it to look like this.
Currently its just updating the current value everytime
My code is as follows:
///add prediction function
Future<String?> addPrediction() async {
var currentUser = FirebaseAuth.instance.currentUser;
var todaysDate = DateTime.now().toString();
var doesExist = await FirebaseFirestore.instance
.collection('collection')
.doc(currentUser!.uid)
.get();
if (doesExist.exists == true) {
FirebaseFirestore.instance
.collection('userMoods')
.doc(currentUser!.uid)
.update({
'Predictions':
FieldValue.arrayUnion([todaysDate,'angry', 'Happy'])
});
}
if (doesExist.exists == false) {
FirebaseFirestore.instance
.collection('userMoods')
.doc(currentUser!.uid)
.set({
todaysDate: FieldValue.arrayUnion(['angry', 'Happy'])
}, SetOptions(merge: false));
}

For adding items you also have to apply the SetOptions but with the merge set to true, like this:
var todaysDate = DateTime.now().toString();
FirebaseFirestore.instance
.collection('userMoods')
.doc(currentUser!.UID).set({
todaysDate : ['angry', 'happy']
}, SetOptions(merge: true));
I did it on my end and I believe they come out the way you want:
The merge: true on the SetOptions what it does is that it appends to the existing document. The set method by default overrides the existing fields unless the merge: true option is there.

Related

how to add new data to existing list in firebase flutter

here is the firebase console
when I tried to add new value using this code
FirebaseFirestore.instance.collection('userCollection').doc(user!.uid).set({
'purchased-id': [oldPurcasedID]
}, SetOptions(merge: true));
and here is the getPurchaseID function
getPurchasedID() async {
DocumentSnapshot pathData = await FirebaseFirestore.instance
.collection('userCollection')
.doc(user!.uid)
.get();
if (pathData.exists) {
Map<String, dynamic>? fetchDoc = pathData.data() as Map<String, dynamic>?;
final purchasedIdMap = await fetchDoc?['purchased-id'];
print('purchased map value : $purchasedIdMap');
return purchasedIdMap;
}
return [];
}
it is replacing the '0'th list value,
how do I add new list under this
I also tried SetOptions(merge: true));. but this didn't help
Use update instead set, which overwrites a document.

Pass variable from function to late stream flutter

I am trying to get getGrupoFav to pass it as a variable to the late Stream<QuerySnapshot> task..., I tried with get but I did not know how to do it and I did not find a solution, I do not know if there is a better way to do it.
the error says
"Try correcting the name to the name of an existing getter, or defining a getter or field named 'getGrupoFav'.
.doc(getGrupoFav)
"
_fetch() async {
final String? userID = FirebaseAuth.instance.currentUser?.uid;
await FirebaseFirestore.instance
.collection("usuarios")
.doc("$userID")
.get()
.then((value) {
String getGrupoFav = value.data()!["grupofav"];
return getGrupoFav;
}).catchError((e) {
print(e);
});
}
late Stream<QuerySnapshot> task = FirebaseFirestore.instance
.collection("grupos")
.doc(getGrupoFav)
.collection("tareas")
.snapshots();
You should build your code something around like below and for the Flutter code syntax please have a look at this documentation
var collection = FirebaseFirestore.instance.collection('usarios');
var userID = FirebaseAuth.instance.currentUser?.uid;
var docSnapshot = await collection.doc(userID).get();
if (docSnapshot.exists) {
Map<String, dynamic> data = docSnapshot.data()!;
var name = data['name'];
}
Then you pass this variable to the document like,
var task = FirebaseFirestore.instance .collection("grupos") .doc(name).snapshots()

I can't fetch data from two different collection consecutively in Firebase with Flutter

I was trying to fetch from two different collection but I got a weird situation. First, I want to fetch a userID from posts collection. Then with that userID, I want to fetch data from users collection.
So, when I fetch from only the posts collection, print command works perfectly fine and prints the userID.
But when I add the users fetch statement that I showed in the code below it doesn't fetch it and shows an empty string (''), and users collection sends an error because I couldn't search the userID. What am I missing here?
class _ProductDetail extends State<ProductDetail> {
String getTitle = '';
String getLocation = '';
String getPrice = '';
String getImage = '';
String getUniversity = '';
String getProfileImage = '';
String getUserName = '';
String getSellerUserID = '';
#override
Widget build(BuildContext context) {
FirebaseFirestore.instance
.collection('posts')
.doc(widget.postID)
.get()
.then((incomingData) {
setState(() {
getTitle = incomingData.data()!['title'];
getPrice = incomingData.data()!['price'];
getImage = incomingData.data()!['postImage'];
});
});
FirebaseFirestore.instance
.collection('posts')
.doc(widget.postID)
.get()
.then((incomingData) {
setState(() {
getSellerUserID = incomingData.data()!['userID'];
});
});
print(getSellerUserID); //statement that will print the userID
//////////////////////IF I DELETE THIS SECTION, IT PRINTS THE USER ID//////////////////
FirebaseFirestore.instance
.collection('users')
.doc(getSellerUserID)
.get()
.then((incomingData) {
setState(() {
getUserName = incomingData.data()!['username'];
getProfileImage = incomingData.data()!['profileImage'];
getUniversity = incomingData.data()!['university'];
getLocation = incomingData.data()!['location'];
});
});
///////////////////////////////////////////////////////////////////////////////////////////////
return Scaffold(
....... rest of the code
Since data is loaded from Firestore asynchronously, the code inside your then blocks is called (way) later then the line after the call to get().
To see this most easily, add some logging like this:
print("Before calling Firestore")
FirebaseFirestore.instance
.collection('posts')
.doc(widget.postID)
.get()
.then((incomingData) {
print("Got data")
});
print("After calling Firestore")
If you run this code, it'll print:
Before calling Firestore
After calling Firestore
Got data
This is probably not the order you expected, but does explain why your next load from the database doesn't work: the getSellerUserID = incomingData.data()!['userID'] line hasn't been run yet by that time.
For this reason: any code that needs the data from Firestore, needs to be inside the then (or onSnapshot) handler, be called from there, or be otherwise synchronized.
So the simplest fix is to move the next database call into the `then:
FirebaseFirestore.instance
.collection('posts')
.doc(widget.postID)
.get()
.then((incomingData) {
var sellerUserID = incomingData.data()!['userID'];
setState(() {
getSellerUserID = sellerUserID;
});
print(sellerUserID);
FirebaseFirestore.instance
.collection('users')
.doc(sellerUserID)
.get()
.then((incomingData) {
setState(() {
getUserName = incomingData.data()!['username'];
getProfileImage = incomingData.data()!['profileImage'];
getUniversity = incomingData.data()!['university'];
getLocation = incomingData.data()!['location'];
});
});
});

Using Transactions but still getting same objects from Firebase

I have a Firebase document "coupon" that has 2 fields inside: an array of strings and an integer as seen below
Currently if a user clicks on a button to get a coupon, it will remove the 0 index at Firebase and show that removed array as coupon code in a Text widget, but if two or more users click on the button at the same time they all get the same string from the array.
This is my button on click code currently:
try {
await FirebaseFirestore.instance
.runTransaction((transaction) async {
DocumentReference
couponCollectionReference =
FirebaseFirestore.instance
.collection('coupons')
.doc(widget.couponNumber);
DocumentReference userCollectionReference =
FirebaseFirestore.instance
.collection('users')
.doc(getUserID());
setState(() {
couponTitle = couponCode[0];
couponBlur = 0.0;
isButtonWorking = false;
});
transaction
.update(couponCollectionReference, {
'coupon_code': FieldValue.arrayRemove(
[couponCode[0]]),
});
transaction
.update(couponCollectionReference, {
'coupons_available':
FieldValue.increment(-1),
});
transaction
.update(userCollectionReference, {
'current_points':
FieldValue.increment(-100),
});
await screenshotController
.capture(
pixelRatio: 2,
delay: Duration(milliseconds: 20))
.then((capturedImage) async {
ShowCapturedWidget(
context, capturedImage!);
}).catchError((onError) {
print(onError);
});
});
} catch (e)
Are transactions the way to go and I'm just not implementing them right or am I using a totally wrong approach ?
In order for the coupon document to be considered part of the transaction, you have to read it from the database through the transaction object (and use the value of coupons from there).
In your code that'd be something like this:
await FirebaseFirestore.instance
.runTransaction((transaction) async {
DocumentReference
couponCollectionReference =
FirebaseFirestore.instance
.collection('coupons')
.doc(widget.couponNumber);
DocumentSnapshot couponDoc = await transaction.get(couponCollectionReference); // 👈
couponCode = (couponDoc.data() as Map<String, dynamic>)['coupons'];
...

Flutter - How to add(create) a nested collection first time and then add fields(update the collection) next time in Firestore

In this method I create a new collection("workouts") the first time a set(exercise set) is saved. A workout will have multiple exercises. So how do I add the next exercises to the same workout?
_saveExerciseSetForUser() {
if (currentUser != null) {
FirebaseFirestore.instance
.collection('users')
.doc(currentUser!.uid)
.collection("workouts")
.doc()
.collection("exercises")
.doc(exerciseId)
.collection("sets")
.doc()
.set({
"setNo.": setCount,
"weight": weightController.text,
"reps": repsController.text,
"toFailure": false
}).then((value) => {
});
}
}
In order to add new exercises to existing workouts, you'll need to keep track of the doc or it's ID for your workout. Once you have the workout ID, you will know the path that you can add the new exercise to. users/$userId/workouts/$workoutId/exercises/$exerciseId/sets
Future<void> _saveExerciseSetForUser([String? workoutId]) async {
if (currentUser == null) {
return;
}
final data = {
"setNo.": setCount,
"weight": weightController.text,
"reps": repsController.text,
"toFailure": false,
};
final workoutDoc = FirebaseFirestore.instance
.collection('users')
.doc(currentUser!.uid)
.collection("workouts")
// if workoutId is null, this will create a new workout
.doc(workoutId);
// save doc id somewhere
final workoutDocId = workoutDoc.id;
await workoutDoc.collection("exercises")
.doc(exerciseId)
.collection("sets")
.doc()
.set(data);
}

Resources