【问题标题】:Firestore transaction update multiple collections in a single transactionFirestore 事务在单个事务中更新多个集合
【发布时间】:2019-12-30 08:57:59
【问题描述】:

如何使用我搜索的单个事务更新 Firestore 中的多个集合,但我没有得到任何答案。是否可以在单个事务中更新多个集合?

我想立即更新 branch.name 在课堂和学生集合中

【问题讨论】:

  • 我不明白,教室和学生之间是什么关系,什么是分支,如果它有Id,为什么不把它移出并放到一个新的集合中?
  • 事务不允许您修改集合中的所有文档。您必须确定要更改的每个文档,并在事务处理程序中单独处理它们。您可以通过这种方式在多个集合之间修改文档。

标签: node.js firebase google-cloud-firestore google-cloud-functions


【解决方案1】:

正如 Node.js 客户端库 update() 方法的文档中所述,它返回一个 Transaction,它“用于链接方法调用”。 (请注意,Admin SDK 的 update() 方法的行为方式完全相同)。

因此,例如,如果在事务中您想从课堂文档中获取一个值,请增加它并使用它来更新来自两个不同集合(classroomsstudents)的两个文档,您可以这样做如下:

const db = firebase.firestore();  //or admin.firestore() in a Cloud Function
const docRef1 = db.collection('classrooms').doc('classroomDocId');
const docRef2 = db.collection('students').doc('studentDocId');


let transaction = db.runTransaction(t => {
  let newNumericValue;
  return t.get(docRef1 )
    .then(doc => {
      newNumericValue = doc.data().numericValue + 1;  //You calculate the new value
      return t.update(docRef1 , {numericValue : newNumericValue});
    }).then(t => {
      return t.update(docRef2 , {numericValue : newNumericValue});
    });
}).then(result => {
  console.log('Transaction success!' + result);
}).catch(err => {
  console.log('Transaction failure:', err);
});

请注意,如果您需要在多次更新之前进行多次读取,“使用事务时,读取操作必须在写入操作之前进行。”


另一方面,如果您只想更新多个文档没有阅读一个或多个值(您在问题中说您“想要更新 branch.在课堂和学生集合中一次性命名“),您不需要使用事务。只需使用batched write,如下:

let batch = db.batch();

let cRef = db.collection('classrooms').doc('classroomDocId');
batch.set(cRef, {branch.name: 'newName'});

let sRef = db.collection('students').doc('studentDocId');
batch.update(sRef, {branch.name: 'newName'});

return batch.commit().then(function () {
  // ...
});

更新您的 cmets

在您的 Cloud Function 中,您可以很好地链接不同的 Firestore 查询(使用 where()),并在每个 then() 中填充批处理,然后在最后一个 then() 中提交批处理。请参阅下面的示例(只需适应正确的查询):

 let batch = admin.firestore().batch();

 return admin.firestore().collection('students').where('branch.id', '==', documentId).get()
 .then((querySnapshot) => {
    querySnapshot.forEach((doc) => { 
        batch.update(doc.ref, {branch: {id: documentId, name: after.name}}); 
    });
    return admin.firestore().collection('student_public').where('branch.id', '==', documentId).get();
 })
 .then((querySnapshot) => {
    querySnapshot.forEach((doc) => { 
        batch.update(doc.ref, {branch: {id: documentId, name: after.name}}); 
    });
    return batch.commit() 
 })
 .catch(err => { console.log('error===>', err); });

【讨论】:

  • 感谢帮助,这是我的批量更新码let batch = admin.firestore().batch(); admin.firestore().collection('students').where('branch.id', '==', documentId).get() .then((querySnapshot) => { querySnapshot.forEach((doc) => { batch.update(doc.ref, {branch: {id: documentId, name: after.name}}); }); return batch.commit(); }).catch(err => { console.log('error===>', err); });
  • 但我的问题是如何使用 where 子句 将相同的逻辑应用于许多文档,例如:let student_public = admin.firestore().collection('student_public').where('branch.id', '==', documentId);let classrooms = admin.firestore().collection('classrooms').where('branch.id', '==', documentId);
  • 我知道您的代码是云函数代码。您应该注意返回 get() 返回的承诺(请参阅 Firebase 视频系列中有关“JavaScript Promises”的 3 个视频:firebase.google.com/docs/functions/video-series,其中解释了这一关键点)。
  • 您可以很好地链接不同的 Firestore 查询(使用 where),然后在每个 then() 中填充批处理,然后在最后一个然后提交批处理。承诺
  • 我已经用一个例子更新了答案。如果您认为我的回答可以解决您的问题,请接受并投票,请参阅stackoverflow.com/help/someone-answers。谢谢!
猜你喜欢
  • 2018-05-11
  • 2019-07-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-10
  • 1970-01-01
  • 1970-01-01
  • 2021-12-09
相关资源
最近更新 更多