What's the best way to delete many (not all) documents from Cloud Firestore?
The official documentation contains information regarding deleting one document and all documents: https://firebase.google.com/docs/firestore/manage-data/delete-data.
What's the best way to delete many (not all) documents from Cloud Firestore?
The official documentation contains information regarding deleting one document and all documents: https://firebase.google.com/docs/firestore/manage-data/delete-data.
To delete multiple documents, you can do a single batched write. The WriteBatch class has a delete() method for this purpose.
The performance to between a single BatchedWrite and multiple DocumentReference.delete calls is similar though, see here. As in: I expect both of them to be plenty enough efficient for a case where the user selects documents to be deleted. If you find out that this is not the case, share the code that reproduces the performance problem.
FirebaseFirestore db = FirebaseFirestore.getInstance();
WriteBatch writeBatch = db.batch();
for (int i=0;i<cartList.size();i++){
DocumentReference documentReference = db.collection("Users").document(cartList.get(i).getProductId());
writeBatch.delete(documentReference);
}
writeBatch.commit().addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
// Do anything here
}
});
As this is the first result when you search for "how to delete multiple documents on Firestore", I wanted to share a working code snippet that not only does what OP is asking, but also splits your batches into chunks to avoid reaching the limit of 500 commits per batch.
const deleteEmptyMessages = async () => {
const snapshot = await firestore.collection('messages').where('text', '==', '').get();
const MAX_WRITES_PER_BATCH = 500; /** https://cloud.google.com/firestore/quotas#writes_and_transactions */
/**
* `chunk` function splits the array into chunks up to the provided length.
* You can get it from either:
* - [Underscore.js](https://underscorejs.org/#chunk)
* - [lodash](https://lodash.com/docs/4.17.15#chunk)
* - Or one of [these answers](https://stackoverflow.com/questions/8495687/split-array-into-chunks#comment84212474_8495740)
*/
const batches = chunk(snapshot.docs, MAX_WRITES_PER_BATCH);
const commitBatchPromises = [];
batches.forEach(batch => {
const writeBatch = firestore.batch();
batch.forEach(doc => writeBatch.delete(doc.ref));
commitBatchPromises.push(writeBatch.commit());
});
await Promise.all(commitBatchPromises);
};
I used batched writes for this. For example I deleted all documents, where the field "text" is empty:
const emptyMessages = await firestore.collection('messages').where("text", "==", "").get()
const batch = firestore.batch();
emptyMessages.forEach(doc => {
batch.delete(doc.ref);
});
await batch.commit();
btnDeleteSomeTasks.setOnClickListener{
for (ids in 0 until mRecyclerView.size){
val currentID = entryAdapter.snapshots.getSnapshot(ids).id
val reference = firestore.collection("allTasks")
.document(user.uid)
.collection("userTasks")
.document(currentID)
reference.delete()
notifyItemRemoved(ids)
}
}
The question didn't provide a specific use case. But...
One common scenario where the user may want to delete multiple documents, would be for example: Removing all of the items from a user's shopping cart. (But not from other user's carts.)
To do this efficiently, you must use a batched write. This allows you to perform multiple delete operations simultaneously.
For example, to delete three documents at once:
WriteBatch batch = db.batch();
batch.delete(db.collection("cartItems").document("item1"));
batch.delete(db.collection("cartItems").document("item2"));
batch.delete(db.collection("cartItems").document("item3"));
batch.commit()
.addOnSuccessListener((result) -> {
Log.i(LOG_TAG, "Selected items have been deleted.");
})
.addOnFailureListener((error) -> {
Log.e(LOG_TAG, "Failed to delete selected items.", error);
});
So if you know the document Ids in advance, this is fairly simple:
public void removeSelectedItemsFromShoppingCart(List<String> itemIds) {
WriteBatch batch = db.batch();
CollectionReference collection = db.collection("cartItems");
for (String itemId : itemIds) {
batch.delete(collection.document(itemId));
}
batch.commit()
.addOnSuccessListener((result) -> {
Log.i(LOG_TAG, "Selected items have been removed.");
})
.addOnFailureListener((error) -> {
Log.e(LOG_TAG, "Failed to remove selected items.", error);
});
}
But if you don't know the document Ids in advance, you may have to query the database first:
public void removeAllItemsFromShoppingCart(String userId) {
db.collection("cartItems")
.whereEqualTo("userId", userId)
.get()
.addOnSuccessListener((querySnapshot) -> {
WriteBatch batch = db.batch();
for (DocumentSnapshot doc : querySnapshot) {
batch.delete(doc.getReference());
}
batch.commit()
.addOnSuccessListener((result) -> {
Log.i(LOG_TAG, "All items have been removed.");
})
.addOnFailureListener((error) -> {
Log.e(LOG_TAG, "Failed to remove all items.", error);
});
})
.addOnFailureListener((error) -> {
Log.e(LOG_TAG, "Failed to get your cart items.", error);
});
}
Note that the code above uses a one-time read, instead of a real-time read. Which is critical here, so it doesn't continue deleting documents after the operation is done.