【问题标题】:firebase transactions you must return a promisefirebase 交易,您必须返回一个承诺
【发布时间】:2019-03-04 15:01:06
【问题描述】:

我试图弄清楚如何从 Angular 6 / typescript 应用程序将事务写入 firebase 数据库。

我用作指导的一个工作示例如下:

const transactions = [];

return db.runTransaction(function(transaction) {
            // const promises = [];
            descriptionsInDB.forEach(dbDescription => {
                if (dbDescription.matched === false) {
                    // item wasn't found, so add the item to the transaction.
                    const phraseItem: PhrasesDB = {
                        query: dbDescription.description,
                        updatedAt: Date.now(),
                        createdAt: Date.now(),
                        workflows: {
                            [workflowId]: true
                        }
                    };
                    const newPhrasesRef = phrasesCol.doc();
                    transactions.push(transaction.set(newPhrasesRef, phraseItem));
                } else {
                    if (dbDescription.data.workflows && dbDescription.data.workflows[workflowId]) {
                        // do nothing, this phrase is already part of the record.
                    } else { // update the workflows that are part of the record.
                        const workflows = { 
                            workflows: {
                                [workflowId]: true
                            }
                         };
                        const phrasesRef = phrasesCol.doc(dbDescription.dbId);
                        transactions.push(transaction.update(phrasesRef, workflows));
                    }
                }
            });

            return Promise.all(transactions); 
        })

我确定的关键部分如下:

1) 创建一个数组来保存您的交易: const transactions = [];

2) 开始事务:return db.runTransactions(function(transaction) {…

3) 使用事务执行数据库查询:transaction.set(newPhraseRef,phraseItem);

4) 将查询返回的交易推送到交易数组:transactions.push(transaction.set(newPhraseRef,phraseItem));

5) 返回一个带有事务数组的承诺:return Promise.all(transaction);

如果我有这个权利,那么我应该能够将这个公式应用于我正在尝试编写的事务,并且它应该可以工作:

        const pendingRef = `Pending/${req.query.inviteId}`;
        const acceptance = {
          'cryptoInvitationAcceptance': req.body.cryptoInvitationAcceptance,
          'reason': (req.body.reason !== undefined ? req.body.reason : '')
        }
return db.runTransaction(function(t) {
          const transArray = [];
          const docRef = db.collection('Pending').doc(req.query.inviteId);
          transArray.push(t.set(docRef, acceptance));
          return Promise.all(transArray);
        }).then(result => {
          console.log('result = ', result);
        }).catch(err => {
          console.log('err = ', err);
        });

但它总是进入 catch 块并打印出消息:

err = 错误:你必须在你的 transaction()-callback 中返回一个 Promise。

但我正在回报一个承诺,不是吗?这行:return Promise.all(transArray) 是我要返回的承诺。没有?

【问题讨论】:

  • 在您发布的示例中,transactions[] 用于从forEach 循环中收集承诺。这就是他们使用Promise.all 的原因。由于您只执行一项操作,因此您应该能够在没有transArray[] 的情况下使用return t.set(docRef, acceptance)。但是,这不应该解决您的问题。

标签: typescript firebase promise transactions angular6


【解决方案1】:

事实证明,这是最好的方法:

      return t.get(pendingDocRef).then(data => {
        t.set(pendingDocRef, acceptance, {merge:true});
      });

get(...) 返回它所要求的承诺,因此 set(...) 不必这样做。

我不喜欢这个。我仍然认为我应该能够自己在事务中进行集合(即没有获取)。

我还发现这种 可以工作:

return t.set(...).commit();

commit() 也返回了一个承诺,但是我得到了非常奇怪的行为:事务一遍又一遍地重复自己,直到它进入 catch 块并出现“事务已过期”的错误。尽管如此,数据会被提交到数据库,所以如果你不介意错误(让它通过),commit() 也可以。

详情见此贴:firebase transaction repeating when committing

【讨论】:

  • 我也遇到了同样的问题,我认为这是有道理的。在写入之前,您应该在事务中加载文档的当前状态。只有这样,交易才真正有意义,因为如果您不这样做,文档可能会同时发生变化。
【解决方案2】:

请阅读Transaction set() 的文档 - 它不会返回承诺。这可能会使 Firestore SDK 感到困惑,因为您返回的 Promise.all() 包含一系列不是承诺的东西。所以它可能认为你返回了一个错误。

您可能根本不需要从事务处理函数返回任何内容。只需致电set() 即可完成。如果您想通过它返回的承诺pass that value out to the caller of runTransaction,您只需要从您的事务处理程序返回一些东西。

顺便说一句,在您的第一个示例中,您不应该将 Promise 收集到在处理函数之外定义的数组中。如果事务处理程序运行不止一次,这可能会导致问题。正如我链接到的文档所说:

请勿在事务函数中修改应用程序状态。 这样做会引入并发问题,因为事务 函数可以运行多次,不保证在 界面线程。

事务之外的数组将被视为“应用程序状态”,因为它不在函数本身内。

【讨论】:

  • 感谢您的回复,道格。我取出事务数组并返回承诺,使其看起来像这样: return db.runTransaction(function(t) {const docRef = db.collection('Pending').doc (
  • 感谢您的回复,道格。我取出事务数组并返回承诺,使其看起来像这样: return db.runTransaction(function(t) {const docRef = db.collection('Pending').doc(req.query.inviteId); t。 set(docRef, 接受); }).then(result => {console.log('result = ', result); }).catch(err => { console.log('err = ', err); } ); ); ...但我仍然遇到同样的错误。我还尝试返回 t.set(docRef, 接受)。我还尝试在 t.set(docRef, 接受) 之后返回一个承诺。我仍然得到同样的错误。这就像 db.runTransaction(...) 不能与 then 链接。
猜你喜欢
  • 1970-01-01
  • 2018-08-13
  • 2015-11-27
  • 2016-01-27
  • 2015-06-05
  • 2014-05-22
  • 2018-09-27
  • 2019-04-25
  • 1970-01-01
相关资源
最近更新 更多