70

I'm looking for a way to clear an entire collection. I saw that there is a batch update option, but that would require me to know all of the document IDs in the collection.

I'm looking for a way to simply delete every document in the collection.

Edit: Answer below is correct, I used the following:

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)
        }
    }
}
ℛɑƒæĿᴿᴹᴿ
  • 4,983
  • 4
  • 38
  • 58
Jake
  • 801
  • 1
  • 6
  • 10

17 Answers17

43

There is now an option in the firebase CLI to delete an entire firestore database:

firebase firestore:delete --all-collections
Kebabman
  • 776
  • 1
  • 7
  • 18
  • 1
    You can get more info with firebase firestore:delete --help – Kebabman Jan 16 '19 at 20:47
  • 1
    Run `firebase login` and add then `firebase firestore:delete --all-collections --project YOUR_PROJECT_NAME` – jmuchiri Feb 15 '19 at 04:51
  • 2
    Be careful not to run this in a production firestore database, as it will wipe out all data... unless that is what you want to do. – user482594 Dec 05 '19 at 00:46
  • 2
    How do I delete documents in a specific collection? Is that possible via the CLI? – Isuru May 29 '20 at 05:34
  • 7
    @Isuru ... you can use `firebase firestore:delete -r COLLECTION_NAME --project FB_PROJECT_NAME` to delete recursively all the documents in the collection (COLLECTION_NAME) – Timo Wagner Mar 05 '21 at 16:36
42

The following javascript function will delete any collection:

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

This works by iterating through every document and deleting each.

Alternatively, you can make use of Firestore's batch commands and delete all in batches of 500 (firestore does not allow more than 500 writes in a single transaction/batch) using the following function:

deleteCollection(path) {
    firebase.firestore().collection(path).listDocuments().then(val => {
        var chunks = []
        for (let i = 0; i < val.length; i += 500) {
            chunks.push(val.slice(i, i + 500))
        }

        for (var chunk of chunks) {
            // Get a new write batch
            var batch = firebase.firestore().batch()
            chunk.map((document) => {
                batch.delete(document)
            })
            batch.commit()
        }
    })
}
Gordin
  • 3
  • 2
Aron Gates
  • 502
  • 4
  • 10
  • 3
    Your code works great, from a Firebase cloud function! But listDocuments() doesn't work from the front end, and listDocuments() isn't a Firestore JavaScript function, as far as I can figure out. Do you have a link to the documentation for listDocuments? – Thomas David Kehoe Mar 15 '19 at 23:08
  • 4
    @ThomasDavidKehoe you can find the documentation here: https://github.com/googleapis/nodejs-firestore/blob/master/types/firestore.d.ts#L1120 This is a NodeJS api and may not work for client side – Aron Gates Mar 18 '19 at 18:03
  • 1
    There is a risk of leaving behind orphaned subcollections. listDocuments() documentation mentions that ... "The document references returned may include references to "missing documents", i.e. document locations that have no document present but which contain subcollections with documents. " – Tony O'Hagan Jul 04 '20 at 06:33
  • 5
    Note that this will fail if your collection has more than 500 documents. `A batched write can contain up to 500 operations` -[batch docs](https://firebase.google.com/docs/firestore/manage-data/transactions#batched-writes). You can overcome this by splitting your `listDocuments()` into groups of 500 – krummens Apr 27 '21 at 22:39
24

There is no API to delete an entire collection (or its contents) in one go.

From the Firestore documentation:

To delete an entire collection or subcollection in Cloud Firestore, retrieve all the documents within the collection or subcollection and delete them. If you have larger collections, you may want to delete the documents in smaller batches to avoid out-of-memory errors. Repeat the process until you've deleted the entire collection or subcollection.

There is even a Swift sample in that documentation, so I recommend you try it.

The Firebase CLI allows you to delete an entire collection with a single command, but it just calls the API to delete all documents in that collection in batches. If this suits your needs, I recommend you check out the (sparse) documentation for the firestore:delete command.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
14

2020 updated answer

You can do it with Node JS - (notice they used process which is a famous object in node not available in Web javascript)

Look at this snippet on Github hosted by firebase. I always had that page pinned to my browser ;)

// [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]
Tilak Madichetti
  • 4,110
  • 5
  • 34
  • 52
7

The cleanest way I have found to delete all documents. The only time I would use this function is when using the emulator and you can simply paste the function into the console:

// 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')

If you find yourself needing this code repeatedly save it as a snippet in Chrome and then you can have easy access to it and won't have to keep pasting the code block into the console. You must run the snippet before it is accessible from the code block. Documentation

Alex Mckay
  • 3,463
  • 16
  • 27
6

versions from v4.10.0 can now bulk delete using this method.

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

It uses BulkWriter to perform the deletes.

g2server
  • 5,037
  • 3
  • 29
  • 40
3

this worked for me by THEODORE above.

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

i dont have the reputaiton to reply directly to his comment. but in addition to his solution if you need to delete a sub-collection using this method just do this.

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

if the docID is auto generated you can use this method below. which is what i was using it for to delete notificaitons for a user when they click the clear all button.

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

the variable can be whatever you're setting the docID with. in my instance it was the user.uid

Strid3r21
  • 317
  • 2
  • 5
2

Tested in 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)
        })
    })
})

0

You have to get all the documents then use batch to delete them in bulk P.S. i prefer try...catch syntax

    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;
    }
}
delavago1999
  • 246
  • 2
  • 11
  • 1
    The catch {} block doesn't accomplish anything in this example; catching an error and immediately throwing it is identical to not catching the error in the first place – iameli Apr 09 '20 at 06:07
0

This is the approach that I took. While it works fine, I'm not sure what other hidden issues it might have.

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;
}
0

listDocuments works only in firebase-admin:

async function deleteCollection(path: string): Promise<FirebaseFirestore.WriteResult[]> {

const batch = firestore.batch();
const documentsInCollection = await firestore.collection(path).listDocuments();
documentsInCollection.map((doc) => batch.delete(doc));

return batch.commit();
};
Lorka
  • 49
  • 1
  • 3
0

There is not a simple way to do this through the API.

To delete multiple documents at once efficiently:

  1. Perform a one-time read of the documents in the collection.
  2. You can use a where clause to limit which documents you retrieve.
  3. Create a write batch.
  4. Queue all of the retrieved documents up for deleting in the batch.
  5. Commit the batch to start deleting documents.
  6. Add appropriate error handlers to listen for errors with reading and deleting documents.

Shown below is an example of how to do this with Android Java.

public void deleteAllMyThings() {
  db.collection("userThings")
    .whereEqualTo("userId", userId)
    .get()
    .addOnSuccessListener((querySnapshot) -> {
      WriteBatch batch = db.batch();
      for (QueryDocumentSnapshot doc : querySnapshot) {
        batch.delete(doc.getReference());
      }

      batch
        .commit()
        .addOnSuccessListener((result) -> {
           Log.i(LOG_TAG, "All my things have been deleted.");
        })
        .addOnFailureListener((error) -> {
          Log.e(LOG_TAG, "Failed to delete all my things.", error);
        });
      })
      .addOnFailureListener((error) -> {
        Log.e(LOG_TAG, "Failed to get all my things.", error);
      });
}
Paul Smith
  • 166
  • 3
  • 13
0

we can be done it by using batch delete

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);
  });
}

To delete an entire collection or subcollection in Cloud Firestore, retrieve all the documents within the collection or subcollection and delete them.

Sadiq PK
  • 17
  • 2
0

If you don't have any large collections, this should work to delete all the collections:

const deleteAllCollections = async () => {
  const db = admin.firestore();

  const cols = await db.listCollections();
  for (const col of cols) {
    const query = await db.collection(col.id).get();
    for (const doc of query.docs) {
      console.log(`Deleting ${doc.id} from collection ${col.id}...`);
      await db.collection(col.id).doc(doc.id).delete();
    }
  }

};

Otherwise, definitely follow the other answers or the docs on:

cbdeveloper
  • 27,898
  • 37
  • 155
  • 336
0

In order to avoid billing and fee on reads/writes, if needed to remove a large collection like 50 millions of documents, this is what worked for me best using firebase CLI:

firebase firestore:delete "/yourCollectionPath" --recursive

Taulant Loshi
  • 464
  • 6
  • 20
-1
db.collection("collectionName")
  .get()
  .then(res => {
    res.forEach(element => {
      element.ref.delete();
    });
  });
THEODORE
  • 917
  • 10
  • 12
-1
const deleteCollection = async (
  collectionRef: CollectionReference<DocumentData>
) => {
  const data = await getDocs(collectionRef);

  data.docs.map(async (document) => {
    await deleteDoc(doc(collectionRef, document.id));
  });
};
Tyler2P
  • 2,324
  • 26
  • 22
  • 31
  • 1
    Your answer could be improved by adding more information on what the code does and how it helps the OP. – Tyler2P Dec 04 '22 at 10:25