Custom APIs
In order to interact with the Firestore Cloud database from our web application, we have to create APIs. In order to re-use these APIs wherever they may be needed, we can wrap them inside Angular services. As mentioned before, services are crucial for sharing data across components.
Fortunately, Firebase does a lot of the hard work for us -- we can wrap their APIs inside ours. Documentation for the full list of these can be found online; below are notable ones.
Adding Data: Use the add method to create a new document in a collection.
this.firestore.collection('collectionName', ref => ref.orderBy('fieldName')).add({ field1: 'value1', field2: 'value2' })
Reading Data: Use the valueChanges method to retrieve data from a collection or document.
this.firestore.collection('collectionName').valueChanges();
this.firestore.collection('collectionName').doc('documentId').valueChanges();
Updating Data: Use the update method to update data in a document.
this.firestore.collection('collectionName').doc('documentId').update({ field1: 'newValue1', field2: 'newValue2' });
Deleting Data: Use the delete method to delete a document.
this.firestore.collection('collectionName').doc('documentId').delete();
Listening for Changes: Use the snapshotChanges method to listen for real-time updates.
this.firestore.collection('collectionName').snapshotChanges();
Querying Data: Use various query methods like where, limit, startAt, and endAt to filter and sort data.
this.firestore.collection('collectionName', ref => ref.where('fieldName', '==', 'value').limit(1)).snapshotChanges();
Transactions: Use the runTransaction method to perform atomic operations.
this.firestore.runTransaction(transaction => { /* transaction code */ });
Note that these methods return Observables. You can subscribe to these Observables to handle the data returned from Firestore.
Animals Service Example
// This function retrieves all animals from the 'Animal' collection in Firestore.
// It returns an Observable of the Animal array.
// Whenever the data changes in Firestore, the Observable emits a new value with the updated data.
getAnimals(): Observable<Animal[]> {
return this.firestore.collection<Animal>('Animal').valueChanges().pipe(
// The tap operator is used here to push the retrieved animals into the animalsSubject stream whenever they change.
tap((animals: Animal[]) => {
this.animalsSubject.next(animals);
})
);
}
// This function retrieves a specific animal by its ID from the 'Animal' collection in Firestore.
// It returns an Observable of the Animal object.
// If no animal is found with the given ID, it throws an error.
getAnimalById(id: string): Observable<Animal> {
return this.firestore.collection<Animal>('Animal').doc(id).valueChanges().pipe(
// The switchMap operator is used here to transform the emissions from the Observable.
// If no animal is found, it throws an error. Otherwise, it returns an Observable of the animal.
switchMap((animal: Animal | undefined) => {
if (!animal) {
throw new Error(`No animal found with id ${id}`);
}
return of(animal);
})
);
}
// This function selects a specific animal by its ID from the 'Animal' collection in Firestore.
// It doesn't return anything but triggers a side effect through the selectedAnimalSource Subject whenever the data changes in Firestore.
selectAnimal(id: string): void {
this.firestore.collection<Animal>('Animal').doc(id).valueChanges().pipe(
// The switchMap operator is used here to transform the emissions from the Observable.
// If no animal is found, it returns an Observable of null. Otherwise, it returns an Observable of the animal.
switchMap((animal: Animal | undefined) => {
if (!animal) {
return of(null);
}
return of(animal);
})
).subscribe((animal: Animal | null) => {
// The subscribed function pushes the selected animal into the selectedAnimalSource stream.
this.selectedAnimalSource.next(animal);
});
}
Last updated
Was this helpful?