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 ?
CodePudding user response:
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); //