如果不同的条件为真,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 如何打破具有不同状态/消息的实时数据库事务?的主要内容,如果未能解决你的问题,请参考以下文章