How to Delete all documents in collection in Firestore with Flutter

Viewed 28205

I have a firestore database. My project plugins:

cloud_firestore: ^0.7.4 firebase_storage: ^1.0.1

This have a collection "messages" with a multiple documents. I need to delete all documents in the messages collection. But this code fail:

Firestore.instance.collection('messages').delete();

but delete is not define

how is the correct syntax?

10 Answers

Ah. The first answer is almost correct. The issue has to do with the map method in dart and how it works with Futures. Anyway, try using a for loop instead like so and you should be good:

firestore.collection('messages').getDocuments().then((snapshot) {
  for (DocumentSnapshot ds in snapshot.documents){
    ds.reference.delete();
  });
});

Update 2021:

Iterate over the QueryDocumentSnapshot, get the DocumentReference and call delete on it.

  • For small number of documents:

    var collection = FirebaseFirestore.instance.collection('collection');
    var snapshots = await collection.get();
    for (var doc in snapshots.docs) {
      await doc.reference.delete();
    }
    
  • For large number of documents (use WriteBatch):

    final instance = FirebaseFirestore.instance;
    final batch = instance.batch();
    var collection = instance.collection('collection');
    var snapshots = await collection.get();
    for (var doc in snapshots.docs) {
      batch.delete(doc.reference);
    }
    await batch.commit();
    

Thanks to @Chris for suggesting the idea of batch write.

As stated in Firestore docs, there isn't currently an operation that atomically deletes a collection.

You'll need to get all the documents, and loop through them to delete each of them.

firestore.collection('messages').getDocuments().then((snapshot) {
  for (DocumentSnapshot doc in snapshot.documents) {
    doc.reference.delete();
  });
});

Note that this will only remove the messages collection. If there are subcollections in this path they will remain in Firestore. The docs also has a cloud function also integration with a Callable function that uses the Firebase Command Line Interface to help with dealing nested deletion.

Really surprised nobody has recommended to batch these delete requests yet.

A batch of writes completes atomically and can write to multiple documents. Batched Writes are completely atomic and unlike Transaction they don’t depend on document modification in which they are writing to. Batched writes works fine even when the device is offline.

A nice solution would be something like:

Future<void> deleteAll() async {
  final collection = await FirebaseFirestore.instance
      .collection("posts")
      .get();

  final batch = FirebaseFirestore.instance.batch();

  for (final doc in collection.docs) {
    batch.delete(doc.reference);
  }
  
  return batch.commit();
}

Remember you can combine delete with other tasks too. An example of how you might replace everything in a collection with a new set of data:

Future<void> replaceAll(List<Posts> newPosts) async {
  final collection = await FirebaseFirestore.instance
      .collection("posts")
      .get();

  final batch = FirebaseFirestore.instance.batch();

  for (final doc in collection.docs) {
    batch.delete(doc.reference);
  }

  for (final post in posts) {
    batch.set(postRef().doc(post.id), post);
  }

  batch.commit();
}

Delete All Documents from firestore Collection one by one:

db.collection("users").document(userID).collection("cart")
    .get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
    public void onComplete(@NonNull Task<QuerySnapshot> task) {
        if (task.isSuccessful()) {
            for (QueryDocumentSnapshot document : task.getResult()) {                                  
                db.collection("users").document(userID).
                    collection("cart").document(document.getId()).delete();
            }
        } else {
        }
    }
});

I think this might help for multiple collections in any document reference

// add ${documentReference} that contains / may contains the ${collectionsList}
_recursiveDeleteDocumentNestedCollections(
      DocumentReference documentReference, List<String> collectionsList) async {
    // check if collection list length > 0
    if (collectionsList.length > 0) {
      // this line provide an async forEach and wait until it finished
      Future.forEach(collectionsList, (collectionName) async {
        // get the collection reference inside the provided document
        var nfCollectionRef = documentReference.collection(collectionName);
        try {
          // get nested collection documents
          var nestedDocuemtnsQuery = await nfCollectionRef.getDocuments();
          // loop through collection documents 
          Future.forEach(nestedDocuemtnsQuery.documents, (DocumentSnapshot doc) async {
            // recursive this function till the last nested collections documents
            _recursiveDeleteDocumentNestedCollections(
                doc.reference, collectionsList);
            // delete the main document
            doc.reference.delete();
          });
        } catch (e) {
          print('====================================');
          print(e);
          print('====================================');
        }
      });
    }
  }

In the latest version of the firebase, you can do following.

_collectionReference.snapshots().forEach((element) {
        for (QueryDocumentSnapshot snapshot in element.docs) {
          snapshot.reference.delete();
        }
      });

In case, if you don't want to use stream (because it will keep deleting until you cancel the subscription). You can go with future delete. Here is the snippet:

final collectionRef = FirebaseFirestore.instance.collection('collection_name');
final futureQuery = collectionRef.get();
await futureQuery.then((value) => value.docs.forEach((element) {
      element.reference.delete();
}));
Firestore.instance.collection("chatRoom").document(chatRoomId).collection("chats").getDocuments().then((value) {
      for(var data in value.docs){
        Firestore.instance.collection("chatRoom").document(chatRoomId).collection("chats")
            .document(data.documentID).delete().then((value) {
          Firestore.instance.collection("chatRoom").document(chatRoomId).delete();

        });
      }
    });

users<Collection> -> userId<Document> -> transactions<Collection> -> List(doc - to be deleted) let's assume this as the collection we will talk about

To delete all documents in a collection along with the collection itself, you need to first delete the List(doc - to be deleted) in a batch

// batch to delete all transactions associated with a user doc
    final WriteBatch batch = FirebaseFirestore.instance.batch();

    // Delete the doc in [FirestoreStrings.transactionCollection] collection
    await _exchangesCollection
        .doc(docId)
        .collection("transaction")
        .get()
        .then((snap) async {
      for (var doc in snap.docs) {
        batch.delete(doc.reference);
      }

      // execute the batch
      await batch.commit();

and then delete the doc userId<Document> which holds the transactions<Collection>

By this way you might have to get rid of the entire userId<Document> itself , but its the only way around to get rid of it completely.

else you can skip the second step of deleting the doc to get rid of the collection, which is totally fine as the collection ref in a doc serves just as the field of the doc.

Related