【问题标题】:Latency compensation and Firestore transactions延迟补偿和 Firestore 事务
【发布时间】:2020-08-09 09:02:02
【问题描述】:

我有一个 onSnapshot 来跟踪集合中的文档:

db.collection('/.../').onSnapshot(querySnapshot=> mylocalvariable = querySnapshot.docs)

现在,我想选择我的用户尚未处理的文档集合中的第一个(按某种顺序)元素。当用户处理完文档后,我使用事务根据用户的需要更新文档(事务对我来说比 .update() 更好,因为我可能有多个用户更改文档的不同部分)。

问题在于,与 .update(会立即更新 mylocalvariable)不同,似乎事务在没有更新 mylocalvariable 的情况下完成。所以,当我去抓取“下一个”文档时,它只是抓取同一个文档,因为函数在变量更新之前运行。

代码示例:

db.collection('/mycollection').onSnapshot(querySnapshot=> mylocalvariable = querySnapshot.docs)

function selectnextrecord(){
  nextrecord = mylocalvariable.find(x=>!x.data().done)
  console.log(nextrecord)
  //expected: Get something different than the current record
  //observed: This is being run with old data, so it returns the same record that I currently have with the old data.
}
let nextrecord;
selectnextrecord();

function submitchanges(){
   let sfDocRef = db.collection('/mycollection').doc(nextrecord.id);
   return db.runTransaction(function(transaction) {
      return transaction.get(sfDocRef).then(function(sfDoc) {
         if (!sfDoc.exists) {
            throw "Document does not exist!";
         }
         transaction.update(sfDocRef, {done:true});
      });
   }).then(function() {
            selectnextrecord();
   }).catch(function(error) {
      console.log("Transaction failed: ", error);
   });
}```

【问题讨论】:

  • 请编辑您的问题以包含我们任何人都可以运行以重现问题的最少、完整的代码。另见how to create a minimal, complete, verifiable example
  • 如果您在此处显示更多相关代码以及对您感到困惑的行为的更详细描述,将会很有帮助。调试日志很好看。
  • 我添加了一些代码,但当然你必须使用一些 Firestore 来运行它。我希望它能澄清问题。 TIA。

标签: google-cloud-firestore transactions


【解决方案1】:

经过documentation后,我认为这是预期的行为。

请勿在事务函数中修改应用程序状态。这样做会引入并发问题,因为事务函数可以运行多次,并且不能保证在 UI 线程上运行。相反,将您需要的信息从交易功能中传递出去

在任何情况下,您都可以过滤没有使用.where() 完成的文档,然后将您的事务放在foreach 中:

db.collection('cities')
.where("done", "==", true)
.get()
.then(snapshot => {
  snapshot.forEach(doc => {
    return db.runTransaction(function(transaction) {
      return transaction.get(sfDocRef).then(function(sfDoc) {
         if (!sfDoc.exists) {
            throw "Document does not exist!";
         }
         transaction.update(sfDocRef, {done:true});
      });
   }).catch(function(error) {
     console.log("Transaction failed: ", error);
   });
  })
})

【讨论】:

  • 我只想在用户检查文档并进行任何需要的更改后将其标记为已完成。如果我将它包装在“哪里”,那不是一次完成所有这些吗?我不认为这是在事务中修改状态的示例。这是为了避免像前端变量 numberofcompleteddocuments 和在事务中执行 numberofcompleteddocuments+=1 这样的事情,如果事务必须重新运行,则会给出错误的数字。
猜你喜欢
  • 2015-08-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-21
相关资源
最近更新 更多