24

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?

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
ALEXANDER LOZANO
  • 1,874
  • 3
  • 22
  • 31

10 Answers10

40

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 this and you should be good:

firestore.collection('messages').getDocuments().then((snapshot) {
  for (DocumentSnapshot ds in snapshot.docs){
    ds.reference.delete();
  };
});
Community
  • 1
  • 1
Ryan Newell
  • 409
  • 3
  • 5
  • 2
    I realize my answer is vague, but I can tell you from experience that using *map* won't work right when working with futures. Using *for* loops instead has solved every issue I've encountered so far. – Ryan Newell Dec 04 '18 at 17:14
  • If you realise that your answer is vague, maybe you could update it with a reference to the flutter documentation? (If they mention this problem/bug/feature anywhere...) – Abby Jan 19 '19 at 21:26
  • Understood. But the answer is vague only because I haven't had the time to dig through the documentation to find out why this is the case. I had the same problem as person with the question and found a solution by simply trying it out. So I was merely attempting to help someone based on what I know works form experience. – Ryan Newell Feb 01 '19 at 17:34
  • Perfectly fine :) Just wanted to point out that a reference like that could help making your answer less vague. – Abby Feb 02 '19 at 10:47
  • 1
    This answer created problems for me. It kept deleting new entries for some reason after this running it, as if the query was stuck in cache some where. – Wesley Barnes Feb 09 '21 at 21:06
32

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.

CopsOnRoad
  • 237,138
  • 77
  • 654
  • 440
12

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.

Joshua Chan
  • 1,797
  • 8
  • 16
5

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();
}
Chris
  • 3,437
  • 6
  • 40
  • 73
1

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.

hmd
  • 23
  • 3
  • for batch commit keep in mind : https://stackoverflow.com/questions/61666244/invalid-argument-maximum-500-writes-allowed-per-request-firebase-cloud-functi – Gopal Kohli Jun 16 '22 at 07:07
0

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

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('====================================');
        }
      });
    }
  }
0

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

_collectionReference.snapshots().forEach((element) {
        for (QueryDocumentSnapshot snapshot in element.docs) {
          snapshot.reference.delete();
        }
      });
Jay Dangar
  • 3,271
  • 1
  • 16
  • 35
  • Tried using this to delete all documents in a collection but for me it would delete a document as soon as its been added. – rejy11 Mar 26 '21 at 14:14
0

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();
}));
AK Ali
  • 152
  • 1
  • 6
0
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();

        });
      }
    });
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
  • 3
    While this code may solve the question, [including an explanation](//meta.stackexchange.com/q/114762) of how and why this solves the problem would really help to improve the quality of your post, and probably result in more up-votes. Remember that you are answering the question for readers in the future, not just the person asking now. Please [edit] your answer to add explanations and give an indication of what limitations and assumptions apply. – Suraj Rao Feb 17 '21 at 14:07