Search Lessons, Code Snippets, and Videos
search by algolia
X
#native_cta# #native_desc# Sponsored by #native_company#

Delete Firestore Collections With Angular and RxJS

Episode 80 written by Jeff Delaney
full courses for pro members



Firebase provides official guidance to delete collections, but it’s not exactly the ideal reactive way to handle things in Angular. In this lesson, I will teach you how to create a an Observable that recursively removes Firestore documents in batches.

In order to follow this lesson you will need AngularFire installed in your project. We will also be using lettable operators introduced in RxJS v5.5.


Source code available to pro members. Learn more



Full source code for firestore collection deletion project.


Example of collections being deleted in Firestore

Deleting Firestore Collections in Angular

First, let’s generate our own Angular service to extend AngularFirestore.

ng g service firestore

Next, let’s flesh out the service by importing the necessary RxJS operators and inject Firestore in the constructor.

import { Injectable } from '@angular/core';
import { AngularFirestore, AngularFirestoreCollection } from 'angularfire2/firestore';
import { Observable } from 'rxjs/Observable';
import { fromPromise } from 'rxjs/observable/fromPromise';
import { expand, takeWhile, mergeMap, take } from 'rxjs/operators';
import * as faker from 'faker'; // optional

@Injectable()
export class FirestoreService {

constructor(private afs: AngularFirestore) { }

// Methods go here
}

Generating Dummy Data for Firestore

For the purposes of this demo, I am using FakerJS to quickly add documents to Firestore. This part is completely optional, but it’s a convenient tool for generating seed data in Firebase.

npm install faker --save

Now we just need a method that will generate the data in a loop and add each document to Firestore.


generateData(path: string, size: number) {
for (const i of Array(size)) {
const dummyData = {
name: faker.commerce.product(),
color: faker.commerce.color(),
brand: faker.company.companyName(),
price: faker.commerce.price()
}

this.afs.collection(path).add(dummyData);
}
}

Recursive Observable to Delete Firestore Collections

You may not be familiar with the expand operator, but it happens to be perfect for this situation. Each delete operation is a batched transaction, which Firebase returns as a promise. For each operation, we query a batch of documents and wait for the delete promise to resolve. This function is called recursively (using expand) until the snapshot.length === 0, at which point takeWhile will trigger the complete signal from the Observable.


deleteCollection(path: string, batchSize: number): Observable<any> {
// ... pro members only
}

// Deletes documents as batched transaction
private deleteBatch(path: string, batchSize: number): Observable<any> {
// ... pro members only
}




deleteCollection(path: string, batchSize: number): Observable<any> {

const source = this.deleteBatch(path, batchSize)

// expand will call deleteBatch recursively until the collection is deleted
return source.pipe(
expand(val => this.deleteBatch(path, batchSize)),
takeWhile(val => val > 0)
)

}

// Deletes documents as batched transaction
private deleteBatch(path: string, batchSize: number): Observable<any> {
const colRef = this.afs.collection(path, ref => ref.orderBy('__name__').limit(batchSize) )

return colRef.snapshotChanges().pipe(
take(1),
mergeMap(snapshot => {

// Delete documents in a batch
const batch = this.afs.firestore.batch();
snapshot.forEach(doc => {
batch.delete(doc.payload.doc.ref);
});

return fromPromise( batch.commit() ).map(() => snapshot.length)

})
)

}


As an added bonus, our RxJS/AngularFire method requires fewer lines of code then the official docs and can be canceled at any time using unsubscribe.

The End

You now have an reactive helper for deleting Firestore documents in batches. Let me know if you have an feedback in the comments or on Slack.