June 11, 2018
  • Tutorials
  • Angular
  • firebase
  • firestore

Building Ionic Apps with Firestore

Jorge Vergara

This is a guest post from Jorge Vegara. Check out his courses covering Ionic, PWAs, and Firebase over at https://jsmobiledev.com.

Firestore is a fully managed NoSQL document-based database for mobile and web. It’s designed to store and sync app data easily. Today, we’ll go over how to manage data from an Ionic app, using Firestore.

What is a Document-oriented database?

Before we jump into things, we need to know how to use it and how it differs from the real-time database.

FireStore is a NoSQL document-oriented database. It’s a big difference from the Real-time database (referred to as RTDB from now on) which is also NoSQL. The RTDB is a gigantic JSON tree where anything goes, and you can set up the information however you want. Simply put, the RTDB let’s developers put what ever data they want, where ever they want.

Firestore, however, is a document-oriented database that offers much more structure than the RTDB. All of your data is stored in objects called documents and these documents can have any number of entries inside (booleans, strings, or even other objects). When grouped together, documents are referred to as collections.

For example, let’s imagine we want to store user information in the database: We would create a collection called users. Inside the collection we’d find objects that hold the information to each user’s profile. Those user profiles are the documents in our database.

A crucial thing to note is that documents can’t have other documents stored inside of them. For example, the user javebratt can’t have a user of booya as one of its properties. But documents can store other sub-collections inside. For example, the user javebratt can have a collection of tasks as one of its properties, and that sub-collection can hold all of the tasks documents.

Setup and Configuration

Now that we have some more insight as to what Firestore is, let’s install it into our Ionic app. The first thing we’ll need to do is install the Firebase SDK.
We could install just the Firebase JS SDK, but since we’re using Angular, we’ll install AngularFire2 as it gives us a nice Observable-based API to work with.

Open your terminal, navigate to your app’s directory and run:

$ npm install angularfire2 firebase --save

After installed, we need to initialize Firebase. For that go to src/app/app.module.ts and import everything we’ll need:

import { AngularFireModule } from 'angularfire2';
import { AngularFirestoreModule } from 'angularfire2/firestore';
import { firebaseConfig } from './credentials';

The AngularFire modules are so that we can access firestore, and the firebaseConfig module is a file we’re using to keep our credentials out of source control.

All you need to do is create the file src/app/credentials.ts and populate it with:

export const firebaseConfig = {
  apiKey: 'Your Firebase Credentials Here',
  authDomain: 'Your Firebase Credentials Here',
  databaseURL: 'Your Firebase Credentials Here',
  projectId: 'Your Firebase Credentials Here',
  storageBucket: 'Your Firebase Credentials Here',
  messagingSenderId: 'Your Firebase Credentials Here'
};

These credentials are available inside your Firebase Console.

By the way, while you’re in the Firebase Console, go into the Database Tab and select Cloud Firestore. Tell it to allow read/write since we’re going to be in development. Keep in mind that you need to set up proper security rules before going to production.

Once we import everything, add it to the imports array inside the @NgModule declaration:

@NgModule({
  declarations: [...],
  imports: [
    BrowserModule,
    IonicModule.forRoot(MyApp),
    AngularFireModule.initializeApp(firebaseConfig),
    AngularFirestoreModule
  ],
  bootstrap: [...],
  entryComponents: [...],
  providers: [...]
})

Now that we got the setup work done, we can access our database inside the app.

Reading Data from FireStore

To read data from the database, we have two options: We can either (1) get a collection of items (think of it as an array of object), or (2) get a specific document from the database (a single object).

To read an object from the database, all you need to do is to create a reference pointing to that document:

constructor(private fireStore: AngularFirestore) {
  this.userDoc = fireStore.doc<any>('userProfile/we45tfgy8ij');
}

Then in our HTML:

<ion-content>
 <pre>{{userDoc | json | async}}</pre>
</ion-content>

The async pipe here is a special pipe in Angular that will automatically handle subscribing and unsubscribing from an observable when the component is created and destroyed.

In our example, we’re pointing to the document with the ID of we45tfgy8ij inside the userProfile collection. If you want to fetch the entire user collection, we could do:

constructor(private fireStore: AngularFirestore) {
  this.userProfileCollection = fireStore.collection<any>('userProfile');
}

You can also query users based on specific properties. Let’s say our users have a property called teamAdmin and we want to fetch the profiles of all the users who are admins of a team.

constructor(private fireStore: AngularFirestore) {
  this.teamAdminCollection = fireStore.collection<any>('userProfile', ref =>
    ref.where('teamAdmin', '==', true));
}

Adding data to FireStore

We are however getting a little be ahead of ourselves, as we first need data in database before we can read.
To push objects to the database we have two main options.

If we want to have a specific ID for the documented we can do:

constructor(private fireStore: AngularFirestore) {
  this.userDoc = fireStore.doc<any>('userProfile/we45tfgy8ij');
  this.userDoc.set({
    name: 'Jorge Vergara',
    email: 'j@javebratt.com',
    // Other info you want to add here
  })
}

If we don’t care about ID, we can just push the documents to the collection and let Firebase auto-generate the ID for us.

constructor(private fireStore: AngularFirestore) {
  this.userProfileCollection = fireStore.collection<any>('userProfile');

  this.userProfileCollection.push({
    name: 'Jorge Vergara',
    email: 'j@javebratt.com',
    // Other info you want to add here
  });
}

Updating data from FireStore

So far we’ve seen that the database API is fairly approachable for new devs and seasoned pros.
To read data, we grab a reference to a collection or document.
To write data, we call set() and pass the data we want to write.
Now can you guess what the method is going to be called to update existing data?

Dramatic Silence

Correct, it’s .update()!

Let’s say a user update some piece of information, we’d first want to grab a reference to that user document, then we’d want to call update() and make any changes needed.

constructor(private fireStore: AngularFirestore) {
  this.userDoc = fireStore.doc<any>('userProfile/we45tfgy8ij');

  this.userDoc.update({
    name: 'Jorge Vergara',
    email: 'j@javebratt.com',
    // Other info you want to add here
  })
}

Remove data from FireStore

For removing data, we have a few different options:

  • Removing a specific document (an object).
  • Removing a property or field from a document.
  • Removing an entire collection.

For example, I deleted a user from FirebaseAuth, and now I want to remove the user profile from the database:

constructor(private fireStore: AngularFirestore) {
  fireStore.doc<any>('userProfile/we45tfgy8ij').delete();
}

Or let’s say we don’t want to delete our user, just one field in their document. In that case, we would fetch the user and call delete on field we want to remove:

constructor(private fireStore: AngularFirestore) {
  fireStore.doc<any>('userProfile/we45tfgy8ij')
  .update({
    age: firebase.firestore.FieldValue.delete()
  });
}

Deleting entire collections however, is a bit trickier. Currently, there’s no way to remove an entire collection in bulk as a safety precaution.

This is because if we were to delete a large amount of data, the Firestore instance would block any other operations until it is completed. Because of this, the Firebase team recommends recursively finding and deleting documents in groups.

There is a “work around” for this, but it’s not recommended as the operation cannot be undone. However, if you need to you can use the Firebase CLI:

$ firebase firestore:delete [options] path...

It will work fine for when you’re removing a bunch of test data, but my advice would be to avoid it when you’re working with production data.

Next Steps

This is a quick overview of how you can use Firestore in your Ionic app. For a more detailed guide, I’ve written a post that will take you through a real-life example explaining everything while we build a Master/Detail view using Ionic for our front-end and Firebase/Firestore for our backend.

You can check that post out here! Thanks!


Jorge Vergara