creating killer mobile applications with ios and couchbase

45
Writing Mobile Applications with Couchbase CodeStock 2016 July 2016

Upload: mike-hagedorn

Post on 11-Apr-2017

60 views

Category:

Software


0 download

TRANSCRIPT

Writing Mobile Applications with

Couchbase

CodeStock 2016 July 2016

Who is this guy?• Mike Hagedorn

• Language Polyglot

• Knoxville, TN

• @mwhagedorn

• http://spkr8.com/s/16930

The Plan

• Relational Datastores• NoSQL Datastores• Couchbase Components• How To Get Started• Demo

– J.K. Rowling

“There's always room for a story that can transport people to another place.”

April 1970

April 1970

what year JFK/Rice Sept 1962

April 1970

Oxygen Tanks

Houston, we’ve had a problem

65 28 5

– Madeleine L’Engle

“Nothing important is completely explicable.”

Data Stores

Relational Data Stores

also created in 1970, E.F. Codd IBM

Relational Example

Why NoSQL?

Changing face of IT Demands

next 20 yrs 40-50% more data, 95% of that will be non structured

BMW/cars as nodes

Couchbase History

Couchbase Terms• Node

• Cluster

• Bucket

• Document

• View

Couchbase Components

Mobile embedded local db with syncGw internet facing componentServer: Ent grade nosql db

Couchbase Server

Couchbase LiteCouchbase Lite is an embedded JSON database that can work standalone, in a P2P network, or as a remote endpoint for Couchbase Server.

EmbeddedAll IO is localSyncs are transparent in backgroundDisconnected operationNO PUSHNO Network

CBL

Device 1

CBL

Device 2

CB Server

Cluster 1with GW!

Sync Gateway

CBL

Device 1

CBL

Device 2

CB Server

Cluster 1

Data Needed Here!

?

Remote Data Center

SGW

Couchbase Model

• An object oriented wrapper on top of CBLDocument

• Somewhat like NSManagedObject

• IOS/OSX only

Couchbase Views

views process the unstructured data to produce an index

live queries

Couchbase Challenges

• Complicated Queries are Hard

• Views!

• Lack of a standard Query Language

show a view javascript

Couchbase Challenges

• Complicated Queries are Hard

• Views!

• Lack of a standard Query Language

show a view javascript

N1QL

possible to use from the REST api

Getting Started

• DL Couchbase Lite Framework

• Add CouchbaseLite.framework to your project

• There is no step 3

Initialization

//AppDelegate CBLManager *manager = [CBLManager sharedInstance]; NSError *error; self.database = [manager databaseNamed:kDBName error: &error]; if (error) { NSLog(@"error getting database %@",error);

exit(-1); }

DatabaseRockets

Name Weight Diameter Cd

alpha 29 25 0.75

hawk 35 30 0.8

a collection of records

Document

{ "coefficientFriction": 0.75, "diameter": 25, "name": "alpha110", "type": "rocket", "weight": 23 }

# Bb6YvfoCH7NIgsVDtgjE7O

Unique IDMay contain binary attachmentstypeless, convention:type

Database View

//RootController or CBModel //Define a view that only returns documents of type ‘kRocketDocType’ CBLView* view = [db viewNamed: @"rockets"];

if (!view.mapBlock) { // Register the map function, the first time we access the view: [view setMapBlock: MAPBLOCK({ if ([doc[@"type"] isEqualToString:kRocketDocType]) emit(doc[@"name"], nil); }) reduceBlock: nil version: @"1"]; }

function (doc,meta) { if(doc.type == “rocket”){

emit(doc.name,null); } }

Map/ReduceCalled on every documentOptional Reduce

not replicated to server

Using Views in your UI// Create a query showing rockets: CBLLiveQuery* query = [[[database viewNamed:@"rockets"] query] asLiveQuery];

// Plug the query into the CBLUITableSource, which will use it to drive the table. // (The CBLUITableSource uses KVO to observe the query's .rows self.dataSource.query = query;self.dataSource.labelProperty = @"name";

// Assumes something like this in your controller @property (nonatomic) IBOutlet UITableView* tableView;

@property (nonatomic) IBOutlet CBLUITableSource* dataSource;

Using Views in your UI// Create a query showing rockets: CBLLiveQuery* query = [[[database viewNamed:@"rockets"] query] asLiveQuery];

// Plug the query into the CBLUITableSource, which will use it to drive the table. // (The CBLUITableSource uses KVO to observe the query's .rows self.dataSource.query = query;self.dataSource.labelProperty = @"name";

// Assumes something like this in your controller @property (nonatomic) IBOutlet UITableView* tableView;

@property (nonatomic) IBOutlet CBLUITableSource* dataSource;

Using Views in your UI// Create a query showing rockets: CBLLiveQuery* query = [[[database viewNamed:@"rockets"] query] asLiveQuery];

// Plug the query into the CBLUITableSource, which will use it to drive the table. // (The CBLUITableSource uses KVO to observe the query's .rows self.dataSource.query = query;self.dataSource.labelProperty = @"name";

// Assumes something like this in your controller @property (nonatomic) IBOutlet UITableView* tableView;

@property (nonatomic) IBOutlet CBLUITableSource* dataSource;

Customizing Table Cells- (void)couchTableSource:(CBLUITableSource*)source willUseCell:(UITableViewCell*)cell forRow:(CBLQueryRow*)row

// Set the cell background and font:

// Configure the cell contents. Map function (above) copies the doc properties into its value, so we can read them without having to load the document.

NSDictionary* rowValue = row.value;BOOL checked = [rowValue[@"check"] boolValue];

if (checked) { cell.textLabel.textColor = [UIColor grayColor];

cell.imageView.image = [UIImage imageNamed:@"checked"]; } else { cell.textLabel.textColor = [UIColor blackColor]; cell.imageView.image = [UIImage imageNamed: @"unchecked"]; }

// cell.textLabel.text is already set, thanks to setting up labelProperty }

Selecting A Row

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { NSLog(@"didSelectRowAtIndexPath"); NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow]; CBLQueryRow *row = [self.dataSource rowAtIndex:indexPath.row]; ASDRocket* rocket = [ASDRocket modelForDocument: row.document];

// Do something with rocket… }

Selecting A Row

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { NSLog(@"didSelectRowAtIndexPath"); NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow]; CBLQueryRow *row = [self.dataSource rowAtIndex:indexPath.row]; ASDRocket* rocket = [ASDRocket modelForDocument: row.document];

// Do something with rocket… }

Adding Items- (IBAction) insertNewObject: (id)sender {

ASDRocket* rocket = [ASDRocket modelForNewDocumentInDatabase:self.database];

rocket.name=name; rocket.weight = 23.0; NSError* error; if (![rocket save: &error]) { return nil; } NSLog(@"Rocket Created");

}

Adding Items- (IBAction) insertNewObject: (id)sender {

ASDRocket* rocket = [ASDRocket modelForNewDocumentInDatabase:self.database];

rocket.name=name; rocket.weight = 23.0; NSError* error; if (![rocket save: &error]) { return nil; } NSLog(@"Rocket Created");

}

Deleting Items-(void) tableView:(UITableView*)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{ if (editingStyle == UITableViewCellEditingStyleDelete){ CBLQueryRow *row = [self.dataSource rowAtIndex:indexPath.row]; ASDRocket* rocket = [ASDRocket modelForDocument: row.document]; NSError* error; if (![rocket deleteDocument: &error]){ NSLog(@"Unable to delete Rocket"); return; } [self.tableView reloadData]; }

}

Replications CBLReplication *pull; CBLReplication *push; h; pull = [_database createPullReplication:_remoteURL]; pull.continuous = YES; pull.network = @"WiFi";

push = [_database createPushReplication:_remoteURL]; push.continuous = YES; pull.network = @"WiFi";

[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(replicationProgress:) name:kCBLReplicationChangeNotification push];

[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(replicationProgress:) name:kCBLReplicationChangeNotification pull];

CBLModel• Maps Objects to documents

@interface ASDRocket : CBLModel

+ (NSString*) docType;

@property (strong) NSString *name; @property (assign) double diameter; @property (assign) double weight; @property (assign) double coefficientFriction;

/** Returns a query for all the rockets in a database. */ + (CBLQuery*) queryRocketsInDatabase: (CBLDatabase*)db;

/** Returns a query for all the rockets with name in a database */ + (CBLQuery*) findInDatabase:(CBLDatabase*)db byName:(NSString *)name;

@end

CBLModel• No types in documents

• convention is to use type field

• Map functions can pick out docs with the right type

if (doc.type == “rocket”){

emit(doc.created, doc.text)

};

Summarywe’ve seenwhy no sql matters, and is neededshown how couch base can enable difficult distributed computingnext a demo….

So What Happened

5 yrs earlier28V components spec to also 65Missed the memo

Demo

• https://github.com/mwhagedorn/couchbase_ios_rockettown

• https://github.com/mwhagedorn/couchbase_osx_rockettown

• Two platforms synching to one database

Questions?• @mwhagedorn

• http://spkr8.com/s/16930

• https://github.com/mwhagedorn/couchbase_ios_rockettown

• https://github.com/mwhagedorn/couchbase_osx_rockettown