我可以在Firestore交易中遍历文档吗?

时间:2019-12-14 05:27:39

标签: firebase google-cloud-firestore

我正在尝试在一个Firestore事务中运行多个文档更新,我想知道这是否是反模式。

我有一个名为“ Group”的文档,其中包含一个名为“ members”的数组,其中包含与用户集合不同的ID。现在,我想遍历所有成员并在一笔交易中更新相应的用户文档。这可能吗?

我尝试使用.forEach()遍历所有成员,但问题是据我所知,.forEach()不支持异步/等待或使用Promise。

1 个答案:

答案 0 :(得分:1)

以下应该可以解决问题:

var firestore = firebase.firestore();

//.....

var groupDocRef = firestore.doc('collectionRef/docRef');

return firestore
          .runTransaction(function(transaction) {
            var arrayOfMemberIds;
            return transaction
              .get(groupDocRef)
              .then(function(groupDoc) {
                if (!groupDoc.exists) {
                  throw 'Group document does not exist!';
                }

                arrayOfMemberIds = groupDoc.data().members;

                return transaction.update(groupDocRef, {
                  lastUpdate: firebase.firestore.FieldValue.serverTimestamp()
                });

              })
              .then(function() {

                arrayOfMemberIds.forEach(function(memberId) {
                  transaction = transaction.update(
                    firestore.collection('users').doc(memberId),
                    { foo: 'bar' }
                  );

                });

                return transaction;
              });
          });

这将起作用,因为update()方法返回了可用于链接方法调用的Transaction实例。

还请注意,我们必须更新初始的groupDoc。否则,将引发以下错误:FirebaseError: "Every document read in a transaction must also be written."。在上面的示例中,我们仅使用时间戳更新了lastUpdate字段。由您决定要执行的更新!


您可以通过如下设置一些安全规则来轻松测试此代码的事务性方面:

service cloud.firestore {
  match /databases/{database}/documents {

    match /collectionRef/{doc} {
      allow read: if true;
    }

    match /users/{user} {
      allow read: if false;
    }

  }
}

由于无法写入users集合,因此Transaction将失败并且collectionRef/docRef文档将被更新。


测试事务方面的另一种(甚至更好的)方法是删除users文档之一。由于update()方法如果应用于不存在的文档会失败,因此整个Transaction将失败。