删除 Firestore 集合中的所有文档

Posted

技术标签:

【中文标题】删除 Firestore 集合中的所有文档【英文标题】:Deleting all documents in Firestore collection 【发布时间】:2018-05-31 08:15:49 【问题描述】:

我正在寻找一种方法来清除整个集合。我看到有一个批量更新选项,但这需要我知道集合中的所有文档 ID。

我正在寻找一种方法来简单地删除集合中的每个文档。

谢谢!

编辑:下面的答案是正确的,我使用了以下内容:

  func delete(collection: CollectionReference, batchSize: Int = 100) 
    // Limit query to avoid out-of-memory errors on large collections.
    // When deleting a collection guaranteed to fit in memory, batching can be avoided entirely.
    collection.limit(to: batchSize).getDocuments  (docset, error) in
      // An error occurred.
      let docset = docset

      let batch = collection.firestore.batch()
      docset?.documents.forEach  batch.deleteDocument($0.reference) 

      batch.commit _ in
        self.delete(collection: collection, batchSize: batchSize)
      
    
  

【问题讨论】:

【参考方案1】:

firebase CLI 中现在有一个选项可以删除整个 Firestore 数据库:

firebase firestore:delete --all-collections

【讨论】:

您可以通过 firebase firestore 获取更多信息:delete --help 运行firebase login 然后添加firebase firestore:delete --all-collections --project YOUR_PROJECT_NAME 小心不要在生产 Firestore 数据库中运行它,因为它会清除所有数据......除非这是您想要做的。 如何删除特定集合中的文档?这可以通过 CLI 实现吗? @Isuru ...您可以使用firebase firestore:delete -r COLLECTION_NAME --project FB_PROJECT_NAME递归删除集合中的所有文档(COLLECTION_NAME)【参考方案2】:

以下 javascript 函数将删除任何集合:

deleteCollection(path) 
    firebase.firestore().collection(path).listDocuments().then(val => 
        val.map((val) => 
            val.delete()
        )
    )

这是通过遍历每个文档并删除每个文档来实现的。

或者,您可以使用 Firestore 的批处理命令并使用以下功能一次性删除所有命令:

deleteCollection(path) 
    // Get a new write batch
    var batch = firebase.firestore().batch()

    firebase.firestore().collection(path).listDocuments().then(val => 
        val.map((val) => 
            batch.delete(val)
        )

        batch.commit()
    )

【讨论】:

您的代码运行良好,来自 Firebase 云功能!但是 listDocuments() 不能从前端工作,并且 listDocuments() 不是 Firestore JavaScript 函数,据我所知。你有 listDocuments 文档的链接吗? @ThomasDavidKehoe 您可以在此处找到文档:github.com/googleapis/nodejs-firestore/blob/master/types/… 这是一个 NodeJS api,可能不适用于客户端 存在留下孤立子集合的风险。 listDocuments() 文档提到...“返回的文档引用可能包括对“缺失文档”的引用,即不存在文档但包含文档子集合的文档位置。” 请注意,如果您的集合包含超过 500 个文档,这将失败。 A batched write can contain up to 500 operations-batch docs。您可以通过将 listDocuments() 分成 500 个组来克服这个问题【参考方案3】:

没有 API 可以一次性删除整个集合(或其内容)。

来自Firestore documentation:

要删除 Cloud Firestore 中的整个集合或子集合,请检索集合或子集合中的所有文档并将其删除。如果您有较大的集合,您可能希望以较小的批次删除文档以避免内存不足错误。重复该过程,直到您删除整个集合或子集合。

该文档中甚至还有一个 Swift 示例,因此我建议您尝试一下。

Firebase CLI 允许您使用单个命令删除整个集合,但它只是调用 API 以批量删除该集合中的所有文档。如果这符合您的需求,我建议您查看(稀疏)documentation for the firestore:delete command。

【讨论】:

但是文档说“不建议从 ios 客户端删除集合。” @FlorianWalther 将删除多个文档的代码放在服务器端。如果您想完全留在 Google 的服务范围内,可以使用例如 Cloud Functions。 查看下方@Kebabman 的评论,了解更新后的 cli 选项以删除所有集合(整个数据库中的所有数据)【参考方案4】:

2020 年更新答案

您可以使用 Node JS 来做到这一点 - (注意他们使用了 process 这是一个著名的节点对象,在 Web javascript 中不可用)

查看由 firebase 托管的 Github 上的 thissn-p。我总是把那个页面固定在我的浏览器上;)

// [START delete_collection]

async function deleteCollection(db, collectionPath, batchSize) 
  const collectionRef = db.collection(collectionPath);
  const query = collectionRef.orderBy('__name__').limit(batchSize);

  return new Promise((resolve, reject) => 
    deleteQueryBatch(db, query, resolve).catch(reject);
  );


async function deleteQueryBatch(db, query, resolve) 
  const snapshot = await query.get();

  const batchSize = snapshot.size;
  if (batchSize === 0) 
    // When there are no documents left, we are done
    resolve();
    return;
  

  // Delete documents in a batch
  const batch = db.batch();
  snapshot.docs.forEach((doc) => 
    batch.delete(doc.ref);
  );
  await batch.commit();

  // Recurse on the next process tick, to avoid
  // exploding the stack.
  process.nextTick(() => 
    deleteQueryBatch(db, query, resolve);
  );


// [END delete_collection]

【讨论】:

PS: 尝试使用 requestAnimationFrame 代替 process tick 并在 web javascript 上运行它;P ~ 说 匿名 像魅力一样工作,不需要从 Electron/Vue 应用程序内部替换 nextTick。【参考方案5】:

我发现删除所有文档的最干净的方法。我唯一会使用这个函数的时候是在使用模拟器时,你可以简单地将函数粘贴到控制台中:

// Paste this in:
function clearCollection(path) 
  const ref = firestore.collection(path)
  ref.onSnapshot((snapshot) => 
    snapshot.docs.forEach((doc) => 
      ref.doc(doc.id).delete()
    )
  )

// Use it like this:
clearCollection('layers')

如果您发现自己需要此代码反复将其保存为 Chrome 中的 sn-p,那么您可以轻松访问它,而不必一直将代码块粘贴到控制台中。您必须先运行 sn-p,然后才能从代码块访问它。 Documentation

【讨论】:

谢谢,在模拟器中,您可以在浏览器的控制台中运行它。【参考方案6】:

在 VueJS 中测试

import db from '@/firebase/init' 

let ref = db.collection('YOUR_COLLECTION_NAME')

db.collection(path).onSnapshot(snapshot => 
    snapshot.docs.forEach(doc => 
        ref.doc(doc.id).delete()
        .catch(error => 
            console.log(error)
        )
    )
)

【讨论】:

是的,已删除完整文档及其子集合。它在 VueJS 3 中也能完美运行。【参考方案7】:

来自v4.10.0 的版本 现在可以使用此方法批量删除。

await firestore.recursiveDelete(firestore.collection('foo'));

它使用BulkWriter 来执行删除操作。

【讨论】:

【参考方案8】:

上面的 THEODORE 对我有用。

db.collection("collectionName")
  .get()
  .then(res => 
    res.forEach(element => 
      element.ref.delete();
    );
  );

我没有直接回复他的评论的声誉。但除了他的解决方案之外,如果您需要使用此方法删除子集合,只需执行此操作即可。

db.collection(`collectionName/docID/subcollection`) //make sure to use backtics
  .get()
  .then(res => 
    res.forEach(element => 
      element.ref.delete();
    );
  );

如果 docID 是自动生成的,您可以在下面使用此方法。当用户单击全部清除按钮时,我用它来删除用户的通知。

db.collection(`collectionName/$variable/subcollection`) 
        .get()
        .then((res) => 
          res.forEach((element) => 
            element.ref.delete();
          );
        );

变量可以是您设置 docID 的任何值。在我的例子中,它是 user.uid

【讨论】:

【参考方案9】:

您必须获取所有文档,然后使用批处理批量删除它们 附言我更喜欢 try...catch 语法

    let deleteInBatch = async (query, size = 100) => 
    try

        let batch = firestore().batch();

        //get documents
        let values = await query.get();
        if(values.size>0)
            values.foreach(value=> 
                batch.delete(value.ref);
            )

            //Delete the documents in bulk
            batch.commit();
            if(values.size>0)
                //Recusively call the function again to finish
                //deleting the rest of documents
                deleteInBatch(query,size);
            
        else
            //exist function
            return;
        
    catch(err)
        throw err;
    

【讨论】:

catch 块在这个例子中没有完成任何事情;捕获错误并立即抛出它与首先不捕获错误相同【参考方案10】:
db.collection("collectionName")
  .get()
  .then(res => 
    res.forEach(element => 
      element.ref.delete();
    );
  );

【讨论】:

【参考方案11】:

这是我采用的方法。虽然它工作正常,但我不确定它可能还有哪些其他隐藏问题。

function deleteCollection(collectionPath, batchSize=400)
    
    let deletePromise = appFirestore.collection(collectionPath).listDocuments()
                    .then( function(docs) 

                        let batch = appFirestore.batch();

                        if(docs.length <= batchSize)
                            docs.map( (doc) => 
                                batch.delete(doc);
                            );
                            batch.commit();
                            return true;
                        
                        else
                            for (let i = 0; i < batchSize; i++)
                                batch.delete(docs[i]);
                            
                            batch.commit();
                            return false;
                        
                    )
                    .then( function(batchStatus) 
                        return batchStatus ? true : deleteCollection(collectionPath, batchSize, debug);
                    )
                    .catch( function(error) 
                        console.error(`Error clearing collections ($error)`);
                        return false;
                    );

    return deletePromise;

【讨论】:

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

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

Firestore使用Rest API更新文档字段

在 Firestore 中使用 Angular 删除集合中的文档

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

Firestore - 云功能 - 获取删除文档的用户的 uid

在不循环的情况下查询 Firestore 集合中的所有文档