Firestore 事务在单个事务中更新多个文档

Posted

技术标签:

【中文标题】Firestore 事务在单个事务中更新多个文档【英文标题】:Firestore transaction update multiple documents in a single transaction 【发布时间】:2018-05-11 23:25:47 【问题描述】:

如何使用我搜索的单个事务更新 Firestore 中的多个文档,但我没有得到任何答案。是否可以在单个事务中更新多个文档?我知道它可以通过批量写入来完成。

【问题讨论】:

你能证明你的馆藏的结构,或者你想阅读/更新什么吗? 我正在通过做示例项目来学习 firebase,所以我只需要在一个事务中更新 2 个文档就可以了,无论如何我找到它 【参考方案1】:

我发现我们可以在一个事务中使用多个 ref:

var userSuhail = db.collection("users").doc("suhail");
var userSam = db.collection("users").doc("sam");
var userJohn = db.collection("users").doc("john");
var userAlfred = db.collection("users").doc("Alfred");
var userAlfredDetails = db.collection('userdetails').doc('Alfred');

db.runTransaction(function (transaction) 
  return transaction.get(userJohn).then(function (sDoc) 
    var age = sDoc.data().age + 1;
    transaction.set(userAlfred, 
      name: 'Alfred',
      age,
      details: userAlfredDetails,
    );
    transaction.set(userAlfredDetails, 
      address: 'Alfred Villa',
    );
    transaction.update( userJohn   ,  age, , );
    transaction.update( userSuhail ,  age, , );
    transaction.update( userSam    ,  age, , );
    return age;
  );
).then(function (age) 
  console.log("Age changed to ", age);
).catch(function (err) 

  console.error(err);
);

通过上面的代码,交易更新了所有用户的年龄。

【讨论】:

正确答案如何?您还没有回答自己的问题 :) 您问“我如何在一次交易中阅读多个文档?”相反,您的解决方案显示了如何在一次读取后写入/更新多个文档... 实际意图是在一个事务中编辑多个文档,要读取多个文档我们可以使用promise All函数。 @suhailc 但是我们可以在事务中读取多个文档并根据读取的内容更新每个文档吗? @rendom 是的,我们可以在一个事务中读取多个文档,例如 db.runTransaction((transaction) => return Promise.all([transaction.get(docref1), transaction.get(docref2)) ]).then((docs) => 让 doc1 = docs[0]; 让 doc2 = docs[1]; @suhailc 如果要获得 docref2 的引用,我需要先读完 docref1,因此我使用的不是 Promise.all,而是:promise1().then(docref2=> promise2 (docref2)) 我得到无法修改已提交的 WriteBatch。【参考方案2】:

您可以使用 firebase 提供的批处理方法。 这就是我使用它来存储对象数组的方式,在新创建的集合中创建多个文档。


export const addCollectionAndDocuments = async (collectionKey, objectToAdd) => 
  console.log(collectionKey, objectToAdd);

  let collectionRef = firestore.collection(collectionKey);
  const batch = firestore.batch();
  objectToAdd.forEach(obj => 
    const newDocRef = collectionRef.doc();
    batch.set(newDocRef, obj);
  );
  return await batch.commit();
;

【讨论】:

【参考方案3】:

概念证明:

var transaction = firestore.runTransaction( t => 
  return t.get(eRef)
    .then(snapshot => 
      snapshot.forEach(doc => 
        var employee = doc.data();
        if(employee.status !== 'Off work') 
          t.update(doc.ref, 
            status: 'Off work',
            returnTime: '8 am'
          )
        
      )
    )
).then(result => 
  console.log('Transaction success!')
).catch(err => 
  console.log('Transaction failure: ', err)
);

【讨论】:

这里的 eRef 是什么?好像是集合引用,但 Transaction.get 只接受文档引用...【参考方案4】:

Cloud Firestore 具有丰富的查询集合选项,是检索多个文档的最佳方式。如果您的数据不是以这些查询工作的方式构建的,那么您需要一个接一个地检索文档。也就是说,如果您的对象有一组指向其他对象的键,则没有有效的查询,您需要在循环中检索它们。

https://firebase.google.com/docs/firestore/query-data/queries

没有(当前)方法可以使用 firestore 在一次操作中更新多个文档。有一个批处理工具,可让您将多个文档更新为单个原子事务,以确保数据完整性。

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

如果这不能回答您的问题,请提供更多详细信息,说明您正在尝试做什么以及您的数据结构。

【讨论】:

我需要的是 3 个文档 1) 用户 2) 项目 3) 类别。当我添加项目时,它必须添加项目并更新类别中的计数并更新用户中的项目列表数组【参考方案5】:

你可以用这个=>

firestore.collection("YOUR_COLLECTION_PATH")
    .get()
    .then(function(querySnapshot) 
        querySnapshot.forEach(function(doc) 
            console.log(doc.id, " => ", doc.data());
        );
    )
    .catch(function(error) 
        console.log("Error getting documents: ", error);
    );

另外,如果你想将 querySnapshot 映射到一个数组中,你可以这样做:

firestore.collection("YOUR_COLLECTION_PATH")
.get()
.then(function(querySnapshot) 
    var arrayDocs = querySnapshot.docs.map(docData=>docData.data())
    console.log(arrayDocs);
)
.catch(function(error) 
    console.log("Error getting documents: ", error);
);

信息在https://firebase.google.com/docs/firestore/query-data/get-data

【讨论】:

此答案不在作为原始问题重点的事务中。

以上是关于Firestore 事务在单个事务中更新多个文档的主要内容,如果未能解决你的问题,请参考以下文章

Firestore - 访问安全规则中的事务/嵌套数据

Swift 和 Cloud Firestore 事务 - getDocuments?

firebase firestore 在事务中添加新文档-transaction.add 不是函数

对多个方法 C# 使用单个事务?

MongoDB事务

Cloud Firestore 事务的限制