Firebase事务和if-then-else行为 [英] firebase transaction and if-then-else behaviour

查看:59
本文介绍了Firebase事务和if-then-else行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的要求有一些变化:

不仅创建/请求/取消整个要约,还对要约的详细信息执行一些操作:

Not only Create/Request/Cancel an entire Offer but do some actions on Offer's details:

这是activeOffers列表中的一个报价:

Here is an offer in the activeOffers list:

activeOffers
    -LKohyZ58cnzn0vCnt9p
        details
            direction: "city"
            seatsCount: 2
            timeToGo: 5
        uid: "-ABSIFJ0vCnt9p8387a"    ---- offering user

用户应该能够要求座位",并且如果成功,则优惠记录应如下所示:

A user should be able to 'ask for seats' and if it's successful the Offer record should look like this:

activeOffers
    -LKohyZ58cnzn0vCnt9p
        details
            direction: "city"
            seatsCount: 1   ----- reduced count
            timeToGo: 5
        uid: "-ABSIFJ0vCnt9p8387a"
    deals
        -GHFFJ0vCnt9p8345b   -----   the userId of asking user
            seatsCount: 1
            status: "asked"

但是在执行如下所示的源代码后,我遇到了3个问题:

But I have 3 problems after executing the source shown below:

(如上图所示,优惠有2个席位,用户要求1个席位)

(as shown above offer has 2 seats and a user asks for 1 seat)

  1. 在我的日志中执行后,我同时拥有减少席位数减1"和席位不足"……即:"if-then-else"的"then"和"else"部分: o

  1. After execution in my log I have BOTH "Reducing seats count by 1" and "Not enought seats"... i.e: the 'then' and 'else' part of 'if-then-else' :o

函数结果为[]-即未创建交易.

function result is [] - i.e. no deal created.

我不确定该如何执行TODO:部分-使用询问的userId作为KEY在dealRef下添加子项(新的交易对象),因为我认为这里不需要自动生成的密钥.

I'm not sure how to do the TODO: part - to add child (the new deal object) under dealsRef using asking userId as KEY because I think I don't need an autogenerated key here.

输入数据具有以下结构:

input data has the following structure:

data
    "uid": "-GHFFJ0vCnt9p8345b",    ----- the userId of asking user
    "id": "-LKohyZ58cnzn0vCnt9p",    ----- the id of offer
    "details":
        "seatsCount": 1

这是我的代码:

dealSeats = function(data) {

const TAG = '[dealSeats]: ';

var details = data.details;
var info = data.info;

var entryRef = db.ref('activeOffers/' + data.id);
var entryDetailsRef = entryRef.child('details');
var seatsCountRef = entryDetailsRef.child('seatsCount');

var success = false;
return seatsCountRef.transaction((current)=>{
    var value = current;
    if (value >= details.seatsCount) {
        success = true;
        value = value - details.seatsCount;
        console.log(TAG + 'Reducing seats count by ' + details.seatsCount);
    } else {
        console.log(TAG + 'Not enought seats');
    }
    return value;
})
.then(()=>{
    var deal = [];
    if (success) {
        console.log(TAG + 'Succes');
        deal.seatsCount = details.seatsCount;
        deal.status = 'asked';
    // TODO: here should add the new deal to dealsRef
        return deal;
    } else {
        console.log(TAG + 'Failure');
        return deal;
    }
})
}

如您所见-我不确定检查交易是否成功的正确方法是什么...

And as you can see - I'm not sure what is the right way to check if transaction is succeeded...

推荐答案

The reference documentation for DatabaseReference.transaction says:

...,直到成功写入而没有冲突为止,或者通过不从更新函数返回值来中止事务.

... until your write succeeds without conflict or you abort the transaction by not returning a value from your update function.

因此,中止事务的方法是不从更新函数返回任何值.这意味着可以将整个第一块简化为:

So the way to abort the transaction is by not returning any value from your update function. That means the entire first block can be simplified to:

seatsCountRef.transaction((current)=>{
    if (current >= details.seatsCount) {
        return value - details.seatsCount;
    }
})

现在,它要么返回新值,要么不返回任何值.后者将使Firebase中止交易.

Now it either returns the new value, or it returns nothing. The latter will then make Firebase abort the transaction.

要检测事务的最终输出,我发现最简单的方法是使用完成回调(而不是Promise),因为它可以在一次调用中为您提供所有参数:

To detect the final output of a transaction, I find it easiest to work with a completion callback (instead of a Promise), since it gives you all parameters in one call:

seatsCountRef.transaction((current)=>{
    if (current >= details.seatsCount) {
        return value - details.seatsCount;
    }
}, function(error, committed, snapshot) {
  if (error) {
    console.log('Transaction failed abnormally!', error);
  } else if (!committed) {
    console.log('We aborted the transaction, because there are not enough seats.');
  } else {
    console.log('Seat count updated');
  }
})

第一个错误情况的最常见原因是必须过于频繁地重试交易,这意味着太多用户试图同时要求获得席位.一种典型的解决方案是放弃,即让客户端稍后重试.

The most common cause for that first error condition will be that the transaction had to be retried too frequently, meaning that too many users are trying to claim seats at the same time. A typical solution here would be to back off, i.e. have the client retry later.

这篇关于Firebase事务和if-then-else行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆