【问题标题】:firebase transaction and if-then-else behaviourfirebase 事务和 if-then-else 行为
【发布时间】:2019-02-01 01:49:48
【问题描述】:

我的要求有一些变化:

不仅创建/请求/取消整个报价,而且对报价的详细信息执行一些操作:

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

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

用户应该能够“要求座位”,如果成功,报价记录应该如下所示:

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个问题:

(如上图提供2个席位,用户要求1个席位)

  1. 在我的日志中执行后,我有“将座位数减 1”和“座位数不足”... 即:“if-then-else”的“then”和“else”部分: o

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

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

输入数据的结构如下:

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;
    }
})
}

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

【问题讨论】:

    标签: javascript firebase firebase-realtime-database transactions


    【解决方案1】:

    reference documentation for DatabaseReference.transaction says:

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

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

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

    现在它要么返回新值,要么什么也不返回。然后后者将使 Firebase 中止事务。

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

    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');
      }
    })
    

    第一个错误情况的最常见原因是事务必须过于频繁地重试,这意味着太多用户试图同时申请席位。此处的典型解决方案是后退,即让客户端稍后重试。

    【讨论】:

    • 感谢您的提示。 1. 部署过程中更新函数没有返回值的警告怎么办? 'warning Expected to return a value at the end of arrow function contrast-return' 2. 使用现有键(询问用户 uid)将子级添加到 dealRef 怎么样?
    • 还有一件事——即使减少座位数是成功的,dealSeats() 也会返回 null。我不确定如何“强制”交易回调将交易变量作为 dealSeats() 结果返回。也许尝试通过席位计数执行事务并在同一代码中为 dealSeats()“构建”结果变量不是一个好主意?
    • 我不确定我是否理解正确。当您在/activeOffers/-LKohyZ58cnzn0vCnt9p/seatsCount 上运行事务时,that 是您可以更新的唯一节点。如果您想在此之外更新节点,您应该在更高级别的节点上运行您的事务。例如。 /activeOffers/-LKohyZ58cnzn0vCnt9p.
    • 啊哈,所以如果我理解正确,我无法在此事务回调中将 deal 节点添加到 -LKohyZ58cnzn0vCnt9p 中。我应该在 -LKohyZ58cnzn0vCnt9p 本身上运行一个事务,在这个事务中我操纵 seatCount 并添加 deal 子节点,对吗?
    • “我应该在 -LKohyZ58cnzn0vCnt9p 本身上运行事务”正确。您应该在树中的最低级别上运行您的事务,该级别涵盖了它需要读取或写入的所有数据。
    猜你喜欢
    • 2011-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多