【问题标题】:Using Transactions but still getting same objects from Firebase使用事务但仍从 Firebase 获取相同的对象
【发布时间】:2022-01-04 14:40:54
【问题描述】:

我有一个 Firebase 文档“优惠券”,里面有 2 个字段:一个字符串数组和一个整数,如下所示

目前,如果用户单击按钮获取优惠券,它将删除 Firebase 中的 0 索引并将删除的数组显示为文本小部件中的优惠券代码,但如果两个或更多用户同时单击该按钮时间他们都从数组中得到相同的字符串。

这是我当前点击代码上的按钮:

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)

交易是要走的路,我只是没有正确实施它们还是我使用了完全错误的方法?

【问题讨论】:

    标签: firebase flutter google-cloud-firestore


    【解决方案1】:

    为了让coupon 文档被视为事务的一部分,您必须通过transaction 对象从数据库中读取它(并从那里使用coupons 的值)。

    在你的代码中是这样的:

    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'];
      ...
    

    【讨论】:

    • 如果我在你的代码中添加最后一行,它会要求一个空检查,如果我实现一个它会抛出 "The operator '[]' is not defined for the type 'Object' . 尝试定义运算符 '[]'" 如果我将 DocumentSnapshot 更改为 DocumentSnapshot 它会抛出下一个:NoSuchMethodError: The method '[]' was called on null. Receiver: null Tried calling: [](0)
    • 这不是我回答的关键,所以那一行肯定有小错误。我现在根据firebase.flutter.dev/docs/firestore/usage#one-time-read 更新了它
    • 成功了,非常感谢!
    • 你好弗兰克,我刚才注意到该解决方案适用于安卓模拟器和真实设备,但如果使用两个真实设备,它们都会再次获得相同的字符串?有什么想法吗?
    • SDK实现事务的方式没有区别,模拟数据库和真实数据库也不应该有任何区别。鉴于最初的问题是通过阅读事务范围内的文档来解决的,因此可能值得打开一个新问题并添加一些日志信息,这些信息包括每个设备在事务中读取的值、写入的内容以及您得到的内容事务完成时在finally 中。
    猜你喜欢
    • 2020-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-05
    • 1970-01-01
    • 2017-02-21
    • 1970-01-01
    相关资源
    最近更新 更多