如果不同的条件为真,Firebase 如何打破具有不同状态/消息的实时数据库事务?

Posted

技术标签:

【中文标题】如果不同的条件为真,Firebase 如何打破具有不同状态/消息的实时数据库事务?【英文标题】:Firebase how to break realtime database transaction with different state/message if different condition is true? 【发布时间】:2019-02-05 02:17:52 【问题描述】:

这是一个好的做法,如果是,正确的方法是什么在不同的情况下以不同的错误状态/消息中断事务?

我有一笔交易通过“优惠”条目进行“座位”预订:

如果以下三个条件之一为真,我想打破它并将状态/消息返回给调用者函数

    如果提问的用户已经预订了此优惠的座位。 如果没有足够的座位。 如果此优惠不存在。

如果一切正常,事务应该正常完成并将状态/消息返回给进行预订的调用者函数。

如果其中一个条件为真,我不确定如何中断交易。

如果我使用 throw new Error('description of the problem.') 那么这将是一个 Exception 并且它不会由事务的 catch() 处理程序处理承诺 而且我不确定如何处理此异常,因为它在这里是一个异步函数。 所以我认为我不应该使用例外。

这就是我的意思:

dealSeats = function(entryRef, data) 
    const TAG = '[dealSeats]: ';
    return entryRef.transaction((entry)=>
        if (entry) 
            if ((entry.deals) && (entry.deals[data.uid])) 
                **? how to break the transaction with state/message 'You already have a deal.' ? and how to handle it below ?**
             else if (entry.details.seatsCount >= data.details.seatsCount) 
                entry.details.seatsCount -= data.details.seatsCount;
                var deal = [];
                deal.status = 'asked';
                deal.details = data.details;
                if (!entry.deals) 
                    entry.deals = ;
                
                entry.deals[data.uid] = deal;
             else 
                **? how to break the transaction with state/message 'Not enought seats.' ? and how to handle it below ?**
            
        
        return entry;
        **? how to check if 'entry' is really null ? i.e. offer does not exists ?** and break and handle it.
    )
    .then((success)=>
        return success.snapshot.val();
    )
    .catch((error)=>
        return Promise.reject(error);
    );

这是我在实时数据库中的数据:

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

这是我的 Postman 发送的测试数据:


 "data": 
  
     "uid": "-FGKKSDFGK12387sddd",    ---- the requesting/asking user
     "id": "-LKpCACQlL25XTWJ0OV_",
     "details":
     
         "direction": "city",
         "seatsCount": 1,
         "timeToGo": 5
     
  

==== 已更新为最终来源 ====

非常感谢 Renaud Tarnec!

所以这是我工作正常的最终来源。如果有人看到潜在的问题,请告诉我。谢谢。

dealSeats = function(entryRef, data) 
    const TAG = '[dealSeats]: ';
    var abortReason;

    return entryRef.transaction((entry)=>
        if (entry) 
            if ((entry.deals) && (entry.deals[data.uid])) 
                abortReason = 'You already made a reservation';
                return; // abort transaction
             else if (entry.details.seatsCount >= data.details.seatsCount) 
                entry.details.seatsCount -= data.details.seatsCount;
                var deal = [];
                deal.status = 'asked';
                deal.details = data.details;
                if (!entry.deals) 
                    entry.deals = ;
                
                entry.deals[data.uid] = deal;
                // Reservation is made
             else 
                abortReason = 'Not enought seats';
                return; // abort transaction
            
        
        return entry;
    )
    .then((result)=> // resolved
        if (!result.committed)  // aborted
            return abortReason;
         else 
            let value = result.snapshot.val();
            if (value) 
                return value;
             else 
                return 'Offer does not exists';
            
        
    )
    .catch((reason)=> // rejected
        return Promise.reject(reason);
    );

唯一的痛苦是在 VSCode 终端中部署期间通过不返回任何值来警告此中止:

warning  Arrow function expected no return value  consistent-return

目前我不确定是否可以对此做任何事情。

【问题讨论】:

【参考方案1】:

查看 Firebase API 参考文档中的此文档:https://firebase.google.com/docs/reference/js/firebase.database.Reference#transaction

以下是此文档中的代码。看看return; 是如何用于中止事务的(文档还说:“你通过不从更新函数返回值来中止事务”)。并注意在事务完成时(在 else if (!committed) 内)调用的 onComplete() 回调函数中如何处理这种特定情况。

// Try to create a user for ada, but only if the user id 'ada' isn't
// already taken
var adaRef = firebase.database().ref('users/ada');
adaRef.transaction(function(currentData) 
  if (currentData === null) 
    return  name:  first: 'Ada', last: 'Lovelace'  ;
   else 
    console.log('User ada already exists.');
    return; // Abort the transaction.
  
, function(error, committed, snapshot) 
  if (error) 
    console.log('Transaction failed abnormally!', error);
   else if (!committed) 
    console.log('We aborted the transaction (because ada already exists).');
   else 
    console.log('User ada added!');
  
  console.log("Ada's data: ", snapshot.val());
);

所以恕我直言,您应该采用相同的模式,并在您的代码中询问“**?如何中断事务”的地方使用 return;

更新:您可以使用变量来区分流产病例,如下所示。如果您通过 Firebase 控制台将值 > 20 的节点 age 添加到 users.ada.name,则将“触发”第一个中止原因。

var adaRef = firebase.database().ref('users/ada');
var transactionAbortionCause;  //new variable
adaRef.transaction(function(currentData) 
  if (currentData === null) 
    return  name:  first: 'Ada', last: 'Lovelace'  ;
   else if (currentData.name.age > 20) 
    transactionAbortionCause = 'User ada is older than 20'; //update the variable
    console.log('User ada is older than 20');
    return; // Abort the transaction.
   else 
    transactionAbortionCause = 'User ada already exists'; //update the variable
    console.log('User ada already exists');
    return; // Abort the transaction.
  
, function(error, committed, snapshot) 
  if (error) 
    console.log('Transaction failed abnormally!', error);
   else if (!committed) 
    console.log('We aborted the transaction because ' + transactionAbortionCause);  //use the variable
   else 
    console.log('User ada added!');
  
  console.log("Ada's data: ", snapshot.val());
);

如果我没记错的话,您也可以使用 Promise 来做到这一点,就像您在代码中所做的那样。该文档说该事务返回一个包含committed: boolean, snapshot: nullable firebase.database.DataSnapshot 的非空firebase.Promise,并解释说这个承诺“可以选择使用而不是onComplete 回调来处理成功和失败”。

所以:

    为你的两起流产案例做return;,并且 读取committed布尔值

您应该能够通过以下方式处理代码中的流产案例

.then((result)=>
    if (result.commited) ...  else  /*abortion!*/
) 

不过我还没有测试过这种方法

【讨论】:

感谢您的回复。我已阅读此文档,但是:1. 正如您所说,我不知道如何区分流产病例。 2. 每当我使用 return; 中止事务时,我在 SVCode 中的 delploy 期间收到警告,但目前我没有关于此警告的任何回复。 我更新了我的答案,提供了一种区分堕胎病例的解决方案。摆脱 VSCode 警告应该不是很难... mm,我只是在想一些带有额外变量的解决方案 :) 很高兴听到你的类似想法。我会尝试,如果有效,我会接受你的回答。关于 VSCode 部署警告 - 也许很容易,但目前我不知道如何摆脱它。 警告箭头函数没有返回值一致返回 这里有一些解决方案的链接。停用 ESLink 不是最好的方法,但如果你不能没有它...***.com/questions/38757069/…github.com/vuejs-templates/webpack/issues/73 非常感谢 :) 它有效。我会接受你的回答,我会用最终的来源更新我的帖子。唯一的“a## 中的痛苦”是部署期间的此警告。我不知道我是否需要担心,但在 VSCode 终端中看到警告很烦人。有什么想法吗?

以上是关于如果不同的条件为真,Firebase 如何打破具有不同状态/消息的实时数据库事务?的主要内容,如果未能解决你的问题,请参考以下文章

如何测试一个条件是不是为真?

如何从具有多个条件的firebase数据库中选择数据[重复]

如何从while循环内的if条件中断while循环?

Angular:如果条件为真,如何更改单元格表的颜色

如果 2 个条件为真,如何正确跳过步骤

从 firebase 检测值并从 superView 中删除(如果为真)