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

Firestore With AngularFire5 Quick Start

Episode 53 written by Jeff Delaney
full courses and content on fireship.io


In this lesson, we are going to use the brand new Firestore NoSQL Database, along with the AngularFire library to perform querying and basic write operations.

Firestore vs. RealtimeDB

Firestore, in many ways, is very similar to the RealtimeDB. It answers the same fundamental question of Where do I save my data?. Firebase wanted to address some the data structuring and querying problems that have annoyed developers. But rather than rebuild the existing API and migrate billions of data points, they added Firestore as an alternative database option in the current platform. I recommend reading this detailed comparison from the Firebase blog.

The jargon is different, but they are both NoSQL databases. Here’s a translation.

  • Firestore ≈ RealtimeDB
  • Collection ≈ List
  • Document ≈ Object
  • Id ≈ Push Key

My Initial Impression of Firestore

Very positive. I wrote an entire post about multi-property data filtering will be made partially obsolete by Firestore - but I couldn’t happier. The query language for the RealtimeDB is hard to work with and Firestore will completely fix that problem. Furthermore, we don’t need to think about global database denormalization anymore - the single most confusing area for developers new to Firebase.

Firestore Pros

  • Expressive queries with where.
  • Ability to query nested data independently.
  • Improved management of data relationships.
  • Cool interface on the Firebase console.
  • Automatic and manual indexing.

Firestore Cons

  • Confusion over which database to use
  • Slightly higher latency on queries (in my experience)
  • Potentially higher usage costs

Overall, the pros easily outweigh the cons and looking forward to building stuff with it.

Upgrading to AngularFire5

At this point, I am assuming you have an Angular project with AngularFire installed. If starting from scratch, follow the official setup guide.

1. Update AngularFire to v5

Update AngularFire2 to AngularFire2 v5


Be careful if working in an existing project as the new AngularFire v5 contains breaking changes. Your existing database code will not work, but you can access the old API via database-deprecated.

Run the following commands, then double-check that angularfire2 is at least version 5.0.0-rc.1 or higher in the package.json file.

npm uninstall angularfire2
npm update angularfire2
npm install angularfire2 --save

2. Include a Project ID

Update your firebaseConfig. It is now necessary to have a projectId when initializing firebase, so make sure it’s included in the config object.

export const environment = {
production: false,
firebaseConfig: {
apiKey: 'XYZ',
authDomain: 'XYZ.firebaseapp.com',
databaseURL: 'https://XYZ.firebaseio.com',
storageBucket: 'XYZ.appspot.com',
projectId: 'XYZ' // <--- make sure project ID is here
}
};

3. Import the Firestore Module

Then make sure to import the AngularFirestoreModule into the NgModule that will be using it.

// ...omitted

import { environment } from '../environments/environment';
export const firebaseConfig = environment.firebaseConfig;

import { AngularFireModule } from 'angularfire2';
import { AngularFirestoreModule } from 'angularfire2/firestore';

@NgModule({
declarations: [
AppComponent,
],
imports: [
BrowserModule,
AngularFireModule.initializeApp(firebaseConfig)
AngularFirestoreModule
],
bootstrap: [
AppComponent
]
})
export class AppModule { }

Single Most Important Change in AngularFire v5

Here’s how we would get a Firebase list or object in past versions of AngularFire

const list: FirebaseListObservable<Item[]> = db.list('items')

list.subscribe(data => console.log(data) )

list.update(data)
list.remove()
/// etc...

In new versions, the Observable is decoupled from the firebase reference (This is true for both Firestore and RealtimeDB).

const collection: AngularFirestoreCollection<Item> = aft.collection('items')

collection.update(data)
collection.delete()

// Notice how the observable is separated from write options

const collection$: Observable<Item> = collection.valueChanges()
collection$.subscribe(data => console.log(data) )

Documents

Firestore Document ≈ RealtimeDB Object

A Firestore document is a its own self-contained tree, so there is less need to flatten or denormalize the entire database. You will still need to think about making documents flat and efficient, but not at the global database level.

Access a Single Document

const document: AngularFirestoreDocument<Item> = afs.document('items/' + someDocId)

const document$: Observable<Item> = document.valueChanges()

Querying Collections

Firestore Collection ≈ RealtimeDB List

Collections are just containers of documents. They have their own query methods that are way more developer-friendly than the realtimeDB. Here are some of the cool things you can do that were previously difficult

// Order ascending
afs.collection('people', ref => ref.orderBy('age') )

// Order descending by numbers or strings
afs.collection('people', ref => ref.orderBy('age', 'desc') )
afs.collection('people', ref => ref.orderBy('name', 'desc') ) // reverse alphabetical

// Limit results
afs.collection('people', ref => ref.orderBy('age').limit(5) )

// Offset by a property
afs.collection('people', ref => ref.orderBy('name').startAt('Jeff') )

There where method

The where method makes it convenient and expressive to make queries. It takes three arguments (1) the property you want to filter by, (2) a logical operator, and (3) the value. Here are a few examples:

// Get items by equality to a property
afs.collection('people', ref => ref.where('name', '==', 'jeff') )

// Get items by range operators
afs.collection('people', ref => ref.where('age', '>=', 5)

// Chain equality for multiple properties
afs.collection('people', ref => ref.where('age', '==', 5) .where('name', '==', 'jeff')

Offline Data

AngularFire has made it incredibly simple to implement offline data into an app. This feature is in an experimental phase, but is expected to work consistently on iOS, Android, and most web browsers (Chrome, Firefox, and Safari).

All you have to do is add enablePersistence() to the import in the NgModule and you’re good to go.

@NgModule({
declarations: [
AppComponent,
],
imports: [
BrowserModule,
AngularFireModule.initializeApp(firebaseConfig)
AngularFirestoreModule.enablePersistence() /// <--- update this line
],
bootstrap: [
AppComponent
]
})
export class AppModule { }

Up Next

I am very excited about Firestore and will be revising many of my past realtimeDB videos to use this new technology.