【问题标题】:Return all docs when all docs are deleted in a collection in Firestore在 Firestore 的集合中删除所有文档时返回所有文档
【发布时间】:2023-03-24 18:19:01
【问题描述】:

我正在使用以下代码删除 Firestore 集合中的所有文档。我的问题是,如何执行一个函数,该函数将在带有已删除文档的数组中返回“deleteCollection”的结果(承诺)?我想遍历所有文档。我当然可以先查询所有数据,循环遍历它,然后执行这个函数,但是数据会被读取两次。

另一种选择是创建一个空的全局变量,删除函数在其中添加文档。但这有多安全?如果我要删除两个巨大的集合,则数组会填充两个不同的文档。那也不对。

我也尝试过修改'new Promise'返回,但是那个函数参数只能包含resolve或reject,不能包含数组。

所以我想要一个调用 deleteCollection 的函数,而不是我想要循环删除的数据。当我只想读取一次数据时,这可能吗?

function deleteCollection(db, collectionRef, batchSize) {
  var query = collectionRef.limit(batchSize);

  return new Promise(function(resolve, reject) {
      deleteQueryBatch(db, query, batchSize, resolve, reject);
  });
}

function deleteQueryBatch(db, query, batchSize, resolve, reject) {
  query.get()
      .then((snapshot) => {
          if (snapshot.size == 0) {
              return 0;
          }
          var batch = db.batch();
          snapshot.docs.forEach(function(doc) {
              batch.delete(doc.ref);
          });
          return batch.commit().then(function() {
              return snapshot.size;
          });
      }).then(function(numDeleted) {
          if (numDeleted <= batchSize) {
              resolve();
              return;
          }
          process.nextTick(function() {
              deleteQueryBatch(db, query, batchSize, resolve, reject);
          });
      })
      .catch(reject);
}

根据 Bergi 的回答编辑

const results = deleteCollection(db, db.collection("deleteme"), 1)
//Now I want to work with the results array, 
//but the function is still deleting documents

function deleteCollection(db, collectionRef, batchSize) {
  return deleteQueryBatch(db, collectionRef.limit(batchSize), batchSize, new Array());
}
async function deleteQueryBatch(db, query, batchSize, results) {
  const snapshot = await query.get();
  if (snapshot.size > 0) {
    let batch = db.batch();
    snapshot.docs.forEach(doc => {
      results.push(doc); <-- the TypeError
      batch.delete(doc.ref);
    });
    await batch.commit();
  }
  if (snapshot.size >= batchSize) {
    return deleteQueryBatch(db, query, batchSize);
  } else {
    return results;
  }
}

【问题讨论】:

标签: javascript node.js firebase promise google-cloud-firestore


【解决方案1】:

首先,避免Promise constructor antipattern:

function deleteCollection(db, collectionRef, batchSize) {
  var query = collectionRef.limit(batchSize);
  return deleteQueryBatch(db, query, batchSize);
}

function deleteQueryBatch(db, query, batchSize) {
  return query.get().then(snapshot => {
    if (snapshot.size == 0) return 0;
    var batch = db.batch();
    snapshot.docs.forEach(doc => { batch.delete(doc.ref); });
    return batch.commit().then(() => snapshot.size);
  }).then(function(numDeleted) {
    if (numDeleted >= batchSize) {
      // I don't think process.nextTick is really necessary
      return deleteQueryBatch(db, query, batchSize);
    }
  });
}

(您可能还想使用async/await 语法,它真正简化了代码并使算法更易于理解:

async function deleteQueryBatch(db, query, batchSize) {
  const snapshot = await query.get();
  if (snapshot.size > 0) {
    let batch = db.batch();
    snapshot.docs.forEach(doc => { batch.delete(doc.ref); });
    await batch.commit();
  }
  if (snapshot.size >= batchSize) {
    // await new Promise(resolve => process.nextTick(resolve));
    return deleteQueryBatch(db, query, batchSize);
  }
}

创建一个空的全局变量,删除函数在其中添加文档。但这有多安全?如果我要删除两个巨大的集合,则数组会填充两个不同的文档。那也不对。

不,不要这样做。只需通过递归调用将您使用结果填充的数组作为参数传递并在最后返回它:

function deleteCollection(db, collectionRef, batchSize) {
  return deleteQueryBatch(db, collectionRef.limit(batchSize), batchSize, []);
}
async function deleteQueryBatch(db, query, batchSize, results) {
  const snapshot = await query.get();
  if (snapshot.size > 0) {
    let batch = db.batch();
    snapshot.docs.forEach(doc => {
      results.push(doc);
      batch.delete(doc.ref);
    });
    await batch.commit();
  }
  if (snapshot.size >= batchSize) {
    return deleteQueryBatch(db, query, batchSize, results);
  } else {
    return results;
  }
}

【讨论】:

  • 感谢您的回答。但是我收到此错误“未处理的承诺拒绝(拒绝 id:1):TypeError:无法读取未定义的属性“推送”。我试图记录它并将 [] 更改为 new Array(),但这并没有帮助。我尝试了 results.push("test"),但仍然出现该错误。此外,deleteCollection 返回一个 void,所以如果 TypeError 消失了,我不确定如何获得结果。我试图在'deleteQueryBatch'之前添加'return',但这不会等待deleteQueryBatch的返回。
  • @J.Doe 啊,我忘记了一堆return 关键字并将results 传递给递归调用。
  • 感谢您抽出宝贵时间创建这个精彩的答案。我联系了支持热线。我希望他们会对您在电子邮件中添加的答案发表评论。谢谢!
猜你喜欢
  • 2020-09-08
  • 2018-11-01
  • 2018-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多