具有多个get

时间:2017-12-05 22:53:49

标签: transactions angularfire2 google-cloud-firestore

我尝试使用可变数量的读取操作来运行事务。 我把read()操作放在update()之前。

https://cloud.google.com/firestore/docs/manage-data/transactions

上阅读Firestore文档
  

"事务由任意数量的get()操作组成,后跟任意数量的写操作,如set(),update()或delete()"

使用交易时,请注意:

  
      
  • 读操作必须在写操作之前进行。
  •   
  • 如果当前编辑影响文档,则调用事务(事务函数)的函数可能会运行多次   交易读取。
  •   
  • 交易功能不应直接修改申请状态。
  •   

但未提供实施。 当我尝试运行下面的代码时,我得到了更多时间运行事务函数,然后我获得了一个异常。 但是,如果我只尝试一次,那么一切顺利。

const reservationCol = this.db.firestore.collection('reservations');
        return this.db.firestore.runTransaction(t => {
         return Promise.all([
            t.get(reservationCol.doc('id1')),
            t.get(reservationCol.doc(('id2')))]
        ).then((responses) => {

        let found = false;
        responses.forEach(resp => {
               if (resp.exists)
                    found = true;
         });
         if (!found)
         {
               entity.id='id1';
               t.set(reservationCol.doc(entity.id), entity);
               return Promise.resolve('ok');
          }
          else
              return Promise.reject('exist');
         });
    });

3 个答案:

答案 0 :(得分:3)

Firestore文档没有说明这一点,但答案隐藏在API参考中:https://cloud.google.com/nodejs/docs/reference/firestore/0.13.x/Transaction?authuser=0#getAll

您可以使用Transaction.getAll()代替Transaction.get()来获取多个文档。你的例子是:

const reservationCol = this.db.firestore.collection('reservations');
return this.db.firestore.runTransaction(t => {
  return t.getAll(reservationCol.doc('id1'), reservationCol.doc('id2'))
    .then(docs => {
      const id1 = docs[0];
      const id2 = docs[1];
      if (!(id1.exists && id2.exists)) {
        // do stuff
      } else {
        // throw error
      }
    })
}).then(() => console.log('Transaction succeeded'));

答案 1 :(得分:0)

我不知道如何用纯Typescript做到这一点,但是我能够找到一个使用Promise的JavaScript example,因此我根据自己的需要进行了调整。它似乎工作正常,但是当我快速运行函数(快速单击一个按钮)时,出现控制台错误,显示为POST https://firestore.googleapis.com/v1beta1/projects/myprojectname/databases/(default)/documents:commit 400 ()。我不清楚这些错误是我应该担心的,还是仅由于事务重试而导致的错误。我发布了my own question about that,并希望得到一些答案。同时,这是我想到的代码:

async vote(username, recipeId, direction) {

  let value;

  if ( direction == 'up' ) {
    value = 1;
  }

  if ( direction == 'down' ) {
    value = -1;
  }

  // assemble vote object to be recorded in votes collection
  const voteObj: Vote = { username: username, recipeId: recipeId , value: value };

  // get references to both vote and recipe documents
  const voteDocRef = this.afs.doc(`votes/${username}_${recipeId}`).ref;
  const recipeDocRef = this.afs.doc('recipes/' + recipeId).ref;

  await this.afs.firestore.runTransaction( async t => {

    const voteDoc = await t.get(voteDocRef);
    const recipeDoc = await t.get(recipeDocRef);
    const currentRecipeScore = await recipeDoc.get('score');

    if (!voteDoc.exists) {

      // This is a new vote, so add it to the votes collection
      // and apply its value to the recipe's score
      t.set(voteDocRef, voteObj);
      t.update(recipeDocRef, { score: (currentRecipeScore + value) });

    } else {

      const voteData = voteDoc.data();

      if ( voteData.value == value ) {

        // existing vote is the same as the button that was pressed, so delete
        // the vote document and revert the vote from the recipe's score
        t.delete(voteDocRef);
        t.update(recipeDocRef, { score: (currentRecipeScore - value) });

      } else {

        // existing vote is the opposite of the one pressed, so update the
        // vote doc, then apply it to the recipe's score by doubling it.
        // For example, if the current score is 1 and the user reverses their
        // +1 vote by pressing -1, we apply -2 so the score will become -1.
        t.set(voteDocRef, voteObj);
        t.update(recipeDocRef, { score: (currentRecipeScore + (value*2))});
      }

    }

    return Promise.resolve(true);

  });

}

答案 2 :(得分:0)

我遇到了同样的问题,因此决定结合使用批处理写入和“常规”读取。 该决定是基于以下事实:我需要进行许多不依赖彼此的阅读。最初,我使用的方法与上面Derrick提出的方法类似,但是事实证明,对于可能的阅读而言,这种方法是不可持续的。 该代码指示每个循环都阻塞到下一个循环。 我要做的是批处理所有读取,以与Promise.all并行运行 这样做的缺点是您无法利用交易功能,但是由于我所偏爱的领域没有变化,因此很有意义 这是我的示例代码

const batch = firestore().batch()
 const readPromises = invoiceValues.map(val => {
                        return orderCollection(omcId).where(<query field>, '<query operation>', <query>).get()
                    })

                    return Promise.all(readPromises).then(orderDocs => {
                  //Perform batch operations here
                        return batch.commit()
                     })

事实证明,这对于许多读取更有效,而且由于我感兴趣的字段不会更改,因此保持安全性