在 Firestore 的集合中删除所有文档时返回所有文档

Posted

技术标签:

【中文标题】在 Firestore 的集合中删除所有文档时返回所有文档【英文标题】:Return all docs when all docs are deleted in a collection in Firestore 【发布时间】:2018-03-29 16:16:10 【问题描述】:

我正在使用以下代码删除 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;
  

【问题讨论】:

避免Promise constructor antipattern! @Bergi 我从 Google Docs 复制了代码:cloud.google.com/firestore/docs/manage-data/delete-data 哎哟。他们当然也应该避免它。在哪里可以使用文档提交错误? @Bergi 我通过此链接与他们联系了几次:firebase.google.com/support/contact/bugs-features 他们通常会很快回复(约 1 天)。 我没有 Firebase 帐户,而且该联系页面需要一个人登录。 【参考方案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 传递给递归调用。 感谢您抽出宝贵时间创建这个精彩的答案。我联系了支持热线。我希望他们会对您在电子邮件中添加的答案发表评论。谢谢!

以上是关于在 Firestore 的集合中删除所有文档时返回所有文档的主要内容,如果未能解决你的问题,请参考以下文章

删除 Firestore 集合中的所有文档

FireStore 不返回所有结果

如何从 Firestore 集合中获取所有文档并将它们返回到数组列表中? [复制]

文档在Firestore中删除后显示

Firestore,检测添加到集合中的新文档等

FLUTTER,FIRESTORE:我有一个流构建器,它从集合中的所有文档中返回某个字段..如何添加查询?