Lesson 12

Getting Data From CouchDB into Ionic

Pulling data into Ionic, and pushing data back to CouchDB

PRO

Lesson Outline

Getting Data From CouchDB into Ionic

We've built a little bit of our application, and we've set up a little bit of our database, but up until this point, they have both existed entirely separately from each other. In this lesson, we are going to bring those two worlds together by doing the following:

  • Set up PouchDB and get it talking with our CouchDB database
  • Set up the Notices and Chats services so that we can retrieve and store data
  • Update the user interface to make use of the services

At the end of this lesson, we should be able to display real data in our application, and also create our own new notices and chats through the application.

Create the Design Documents

Before we start pulling data into our application, we are going to set up the views we need in our CouchDB database. As we discussed in the last lesson, we can create a view inside of a design document in CouchDB to create a list of specific data based on a map function.

Our views are going to be very simple. We want to be able to pull in a list of notices into our notices page, and we want to be able to pull in a list of chats into our chats page, so we will create two separate views to achieve this. One view will list all of the notices, and another view will list all of the chats.

We are going to create two separate design documents to do this, one for chats and one for notices. This is not necessary, we could just create a single 'app' design document that implemented both of the views, but creating separate design documents helps to keep things organised. We will also be adding other features to the design documents later, so it is going to be cleaner to keep things separated. But I do want to emphasise the fact that it doesn't matter if we have a "notices" design document and a "chats" design document, the views in these design documents will still run on all documents in the database (both chats and notices).

Add the following document to your CouchDB database (you can just create this as a normal document like any other, you don't need to create it anywhere specific):

{
  "_id": "_design/notices",
  "language": "javascript",
  "views": {
    "by_date_updated": {
      "map": "function(doc){ if(doc.type === 'notice'){emit(doc.dateUpdated);} }"
    }
  }
}

This is our notices design document, and we have created a by_date_updated view. We already discussed the purpose of this in the last lesson, but to quickly recap: this map function will create a view that contains all of the notices in the database, and it will use the dateUpdated field as the key. This will allow us to sort the notice documents by the date they were last updated.

NOTE: Be careful using quotation marks when adding functions to design documents. In the example above we use single quotes for 'notice' but if you use double quotes you need to make sure to escape it with a slash \" so that it doesn't break the string used as the map function.

Add the following document to your CouchDB database:

{
  "_id": "_design/chats",
  "language": "javascript",
  "views": {
    "by_date_created": {
      "map": "function(doc){ if(doc.type === 'chat'){emit(doc.dateCreated);} }"
    }
  }
}

This is the design document for chats and it is almost exactly the same as the notices design document, except that we use the dateCreated field as the key. It will not be possible to update chats once they are created, so we don't have a dateUpdated field.

Implement the Data Service

We've done everything that needs to be done on CouchDB's end to start pulling data into our application, so let's implement the Data provider now. As I mentioned earlier, we want the Data provider to handle most of the integration with PouchDB and CouchDB so that we can abstract the implementation details away from the rest of our application as much as possible. The data provider will be the middleman between our application and the database.

Let's create the data provider now.

Modify src/app/services/data.service.ts to reflect the following:

import { Injectable } from '@angular/core';
import PouchDB from 'pouchdb-browser';

@Injectable({
  providedIn: 'root',
})
export class DataService {
  public db: PouchDB.Database = null;
  private remote: string;

  constructor() {}

  initDatabase(remote: string): void {
    this.db = new PouchDB('hangz-app', {
      auto_compaction: true,
    });

    this.remote = remote;
    this.initRemoteSync();
  }

  initRemoteSync(): void {
    let options = {
      live: true,
      retry: true,
    };

    this.db.sync(this.remote, options);
  }

  createDoc(doc: any): Promise<any> {
    return this.db.post(doc);
  }

  updateDoc(doc: any): Promise<any> {
    return this.db.put(doc);
  }

  deleteDoc(doc: any): Promise<any> {
    return this.db.remove(doc);
  }
}

We make PouchDB's functionality available in this class by importing it:

import PouchDB from 'pouchdb-browser';

We use that to create a new local PouchDB database called hangz-app, with the auto_compaction option set to true (this basically helps keeps our database tidy over time by removing old revisions). If the database does not already exist locally it will create it, but if it does already exist then it will just use that existing database.

This is triggered within an initDatabase method that we will call at some point during the startup of the application, and we will pass in the URL for the remote CouchDB database into it. We then use that URL in the initRemoteSync method, which sets up the live sync between the local PouchDB database and the remote CouchDB database.

In the options for the sync, we set both live and retry to true. The live option will subscribe to changes so that when there are any changes they will automatically be replicated. The retry option will make PouchDB reattempt replication if a failure occurs. This is especially important for getting this to work in the case of a user being offline and then coming back online - the initial replication would fail whilst they are offline, but once they come online the connection to the remote database can be established.

We have also created three methods for creating, updating, and deleting documents. We will be able to pass in documents to these methods, and then the data provider will handle performing the operations.

There's a subtle difference between posting and putting a document, you may notice that for creating documents we use post but for updating documents we use put. You should use put in cases where you know the _id of a document, i.e. cases where you are updating an existing document, or when you are creating a new document but you want to specify the _id yourself. If you are creating a new document and not supplying an _id, you should use post.

PRO

Thanks for checking out the preview of this lesson!

You do not have the appropriate membership to view the full lesson. If you would like full access to this module you can view membership options (or log in if you are already have an appropriate membership).