Last week, I was super excited to figure out how to provision IBM Cloudant / CouchDB databases during an Auth0 login transaction . This allows me to drive a database-per-user architecture on the remote side; and, thanks to PouchDB, I can do the same thing on the local side. The last piece of the puzzle was being able to keep the remote Cloudant database and the local PouchDB database in sync. Thankfully, the CouchDB replication API, leveraged by the PouchDB client library, makes this super easy!

Run this demo in my javascript Demos project on GitHub .

Replication between two CouchDB-compatible databases happens in a single direction - a source database replicates to a target database. But, thanks to the magical master-master replication capabilities of CouchDB, bi-directional replication can be achieved by essentially performing uni-directional replication in both directions. In the PouchDB client library, they even provide a convenience method for this bi-directional replication setup, called .sync().

Syncing Local PouchDB Data With Remote IBM Cloudant Database In Angular 2.4.1

The .sync() method can perform replication in a discrete, one-off manor; or, it can perform "live" syncing in which the target database is "long polled" for updates that need to be replicated back down to the source database. In my exploration, I am performing discrete sync operations for a few reasons:

First, I don't believe that IBM Cloudant allows for "live sync" by default (though I also believe that I may be confusing the terminology, assuming that "continuous replication" and "live sync" are the same thing). Based on the documentation, it appears to be disabled for both performance and cost reasons - both of which relate to reducing network activity. Second, I think it might make more sense from an "offline first" web application perspective to perform synchronization at specific points in the application life-cycle. Focus on the local experience first; then, figure out when it makes sense to sync to the remote database (balancing user experience with an actual dollars-and-cents cost).

To explore data synchronization across CouchDB instances, I took my previous Angular 2 demo in which I deferred PouchDB configuration until after login ; then, I added some remote database credentials (hard-coded) and an explicit syncing function. In this case, since the demo has two "users", I went into Cloudant, provisioned two new databases and, for each database, assigned a new API Key that had read, write, and replicate permissions.

First, let's look at the Angular 2 root component. In this component, the user can log into the application using one of two hard-coded identities. Once "authenticated", both a local and remote PouchDB database are provisioned and the list of friends is loaded. The user can then interact with the list of friends, adding and deleting entires. These mutations are performed against the local PouchDB database only. When the user selects to "sync" the two databases, however, changes are pushed and pulled between the local and remote databases and the list of friends is re-rendered:

// Import the core angular services. import { Component } from "@angular/core"; // Import the application components and services. import { FriendService } from "./friend.service"; import { IFriend } from "./friend.service"; import { ISyncResult } from "./pouchdb.service"; import { PouchDBService } from "./pouchdb.service"; interface IAddForm { name: string; @Component({ moduleId:, selector: "my-app", styleUrls: [ "./app.component.css" ], template: <!-- BEIGN: Logged-out view. --> <template [ngIf]="( user === null )"> <ul> <li> <a (click)="login( 'ben' )">Login as Ben</a> </li> <li> <a (click)="login( 'kim' )">Login as Kim</a> </li> </ul> </template> <!-- END: Logged-out view. --> <!-- BEIGN: Logged-in view. --> <template [ngIf]="( user !== null )"> <p> <strong>Logged-in as {{ user }}</strong>. <a (click)="logout()">Logout</a> &nbsp;|&nbsp; <a (click)="syncData()">Sync remote database</a>. </p> <ul> <li *ngFor="let friend of friends"> {{ }} &mdash; <a (click)="deleteFriend( friend )">Delete</a> </li> </ul> <div class="form"> <input type="text" [value]="" (input)=" = $" (keydown.Enter)="processAddForm()" /> <button type="button" (click)="processAddForm()">Add Friend</button> </div> </template> <!-- END: Logged-in view. --> }) export class AppComponent { public addForm: IAddForm; public friends: IFriend[]; public user: string; private friendService: FriendService; private pouchdbService: PouchDBService; // I initialize the component. constructor( friendService: FriendService, pouchdbService: PouchDBService ) { this.friendService = friendService; this.pouchdbService = pouchdbService; this.addForm = { name: "" }; // To start out, the Friends collection will be empty; and, it must remain // empty until the user logs-in because, until then, the PouchDB database has // not been configured and we won't know where to read data from. this.friends = []; this.user = null; // --- // PUBLIC METHODS. // --- // I delete the given friend from the list. public deleteFriend( friend: IFriend ) : void { this.friendService .deleteFriend( ) .then( () : void => { this.loadFriends(); }, ( error: Error ) : void => { console.log( "Error:", error ); // I login the user with the given identifier. public login( userIdentifier: string ) : void { // In


主题: CouchDBIBMGitJavaScriptGitHubJavaUBETH
tags: gt,lt,database,user,PouchDB,friend,sync,remote
本文标题:Syncing Local PouchDB Data With Remote IBM Cloudant Database In Angular 2.4.1

技术大类 技术大类 | 数据库(综合) | 评论(0) | 阅读(191)