Mobile workshop: Couchbase lite in-depth

71
COUCHBASE LITE INDEPTH James Nocentini, Developer Advocate, Couchbase

Transcript of Mobile workshop: Couchbase lite in-depth

Page 1: Mobile workshop: Couchbase lite in-depth

COUCHBASE  LITE  IN-­‐DEPTH

James  Nocentini,  Developer  Advocate,  Couchbase

Page 2: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc.

This  morning

▪Using  Documents  and  Revisions  

▪Utilising  convenience  Data  Model  APIs  

▪ Creating  Couchbase  Lite  Views  

▪Querying  Views  

▪ Live  Queries

2

Page 3: Mobile workshop: Couchbase lite in-depth

ToDo  Lite

Page 4: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc. 4

Page 5: Mobile workshop: Couchbase lite in-depth

Demo

Page 6: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc.

Data  Model  

6

Page 7: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc. 7©2015&Couchbase&Inc.

Overview

▪ Couchbase&Mobile&features&▪ Focus&on&Couchbase&Lite:&▪ Installing&and&running&a&sample&app&▪ A&tour&of&Couchbase&Lite’s&architecture&and&API&▪…as&shown&in&the&sample&app’s&code&▪Next&steps

2

Page 8: Mobile workshop: Couchbase lite in-depth

1.  Database

Page 9: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc. 9©2015&Couchbase&Inc.

InitializationDemoAppDelegate.m:61

!!!!//"Initialize"Couchbase"Lite"and"find/create"my"database:!!!!!NSError*!error;!!!!!self.database!=![[CBLManager!sharedInstance]!createDatabaseNamed:!kDatabaseName!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!error:!&error];!!!!!if!(!self.database)!{!!!!!!!!![self!showAlert:!@"Couldn't!open!database"!error:!error!fatal:!YES];!!!!!!!!!return!NO;!!!!!}!

18

Page 10: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc.

Database

10

public class Application extends android.app.Application {

@Overridepublic void onCreate() { super.onCreate(); }

}

Page 11: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc.

Database

11

public class Application extends android.app.Application {

@Overridepublic void onCreate() { super.onCreate(); Manager manager = new Manager(new AndroidContext(getApplicationContext()), Manager.DEFAULT_OPTIONS); }

}

Page 12: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc.

Database

12

public class Application extends android.app.Application {

@Overridepublic void onCreate() { super.onCreate(); Manager manager = new Manager(new AndroidContext(getApplicationContext()), Manager.DEFAULT_OPTIONS); Database database = manager.getDatabase("dbname");}

}

Page 13: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc. 13©2015&Couchbase&Inc.

Manager

▪ TopJlevel&object,&usually&a&singleton&▪ A&collection&of&named&databases&▪ Locates&databases&in&filesystem

19

Page 14: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc. 14©2015&Couchbase&Inc.

Database

▪Namespace&for&documents&▪ Contains&views&and&their&indexes&▪ Contains&validation&functions&▪ Source&and&target&of&replication

21

Page 15: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc.

Database

15

Page 16: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc. 16©2015&Couchbase&Inc.

Interesting+Document+Facts

▪ JSON&allows&nested&data&structures&(arrays,&maps)&

▪ Schemaless&—&Documents&needn’t&have&the&same&structure&

▪Different&types&of&docs&can&coexist&in&a&database&▪ “type”&property&is&a&common&convention&

▪Documents&are&versioned&

▪Optimistic&concurrency&control&(MVCC)

22

Page 17: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc.

Documents

17

Map<String, Object> properties = new HashMap<String, Object>();properties.put("type", "list");properties.put("title", title);properties.put("created_at", currentTimeString);properties.put("owner", "profile:" + userId);properties.put("members", new ArrayList<String>());

Page 18: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc.

Documents

18

Map<String, Object> properties = new HashMap<String, Object>();properties.put("type", "list");properties.put("title", title);properties.put("created_at", currentTimeString);properties.put("owner", "profile:" + userId);properties.put("members", new ArrayList<String>());

Document document = database.createDocument();

Page 19: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc.

Documents

19

Map<String, Object> properties = new HashMap<String, Object>();properties.put("type", "list");properties.put("title", title);properties.put("created_at", currentTimeString);properties.put("owner", "profile:" + userId);properties.put("members", new ArrayList<String>());

Document document = database.createDocument();document.putProperties(properties);

Page 20: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc.

Documents

20

Document document = database.getDocument("task-123");

Page 21: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc.

Documents

21

Document document = database.getDocument("task-123");String title = document.getProperty("title");

Page 22: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc.

Documents

22

Document document = database.getDocument("task-123");String title = document.getProperty("title");Map<String, Object> properties = doc.getProperties();String owner = (String) properties.get("owner");

Page 23: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc.

Documents

{ "_id": "123", "type": "list", "title": "Today’s list", "owner": "1234567890", "members": [

"0987654321","0192837465"

]}

23

Page 24: Mobile workshop: Couchbase lite in-depth

Models

Page 25: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc.

Models

25

@interface Task : CBLModel

@end

@implementation Task

@end

Page 26: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc.

Models

26

@interface Task : CBLModel

@property NSString *title;

@end

@implementation Task @dynamic title;

@end

Page 27: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc.

Models

27

@interface Task : CBLModel

@property NSString *title; @property bool checked;

@end

@implementation Task @dynamic title, checked;

@end

Page 28: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc.

Models

28

@interface Task : CBLModel

@property NSString *title; @property bool checked; @property (weak) List *list_id;

@end

@implementation Task @dynamic title, checked, list_id;

@end

Page 29: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc.

Models

29

Task *task = [Task modelForNewDocumentInDatabase:self.database];

New  model

New  model  for  

Saving  the  model

[task save:nil];

Task *task = [Task modelForDocument:self.database];

Page 30: Mobile workshop: Couchbase lite in-depth

©2015  Couchbase  Inc. ‹#›

Page 31: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc. 31

2.+Views+&+Queries

Page 32: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc. 32©2015&Couchbase&Inc.

Creating+A+Database+ViewRootViewController.m:50

!!!!//"Define"a"view"with"a"map"function"that"indexes"toAdo"items"by"creation"date:!!!!![[theDatabase!viewNamed:!@"byDate"]!setMapBlock:!MAPBLOCK({!!!!!!!!!id!date!=!doc[@"created_at"];!!!!!!!!!if!(date)!!!!!!!!!!!!!emit(date,!doc);!!!!!})!version:!@"1.1"];!

Not a UIView — a database “view” is like an index.

25

Page 33: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc. 33©2015&Couchbase&Inc.

Map/Reduce+Views

▪ Concept&from&functional&programming,&via&Google&

▪ AppJdefined&map+function&operates&on&documents&

▪ doc&&⟼&&{&(key,&value)&…}&

▪ Its&output&generates&an&index&ordered&by&key&▪ Index&rows&can&be&aggregated&by&a&reduce+function+▪ Index&is&queried&by&key&or&key&range

26

Page 34: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc. 34©2015&Couchbase&Inc.

Map/Reduce+Indexing

!!!!!!!

emit(doc.created,!!!!!!doc.title)

key value docID

“2013D03D12” “taxes” “doc17”

“2013D09D30” “call)mom” “doc62”

“2013D10D17” “cat)food” “doc82”

“2013D10D17” “tea)bags” “doc83”

“2013D10D22” “upgrade” “doc90”

index

all documents

map function

View+“byDate”

27

Page 35: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc. 35©2015&Couchbase&Inc.

Creating+A+Database+ViewRootViewController.m:101

!!!!//"Define"a"view"with"a"map"function"that"indexes"toAdo"items"by"creation"date:!!!!![[theDatabase!viewNamed:!@"byDate"]!setMapBlock:!MAPBLOCK({!!!!!!!!!id!date!=!doc[@"created_at"];!!!!!!!!!if!(date)!!!!!!!!!!!!!emit(date,!nil);!!!!!})!version:!@"1.1"];!

Not a UIView — a database “view” is like an index.

28

Page 36: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc. 36©2015&Couchbase&Inc.

Driving+the+Table+from+a+View+QueryRootViewController.m:101

!!!!//"Create"a"query"sorted"by"descending"date,"i.e."newest"items"first:!!!!!CBLLiveQuery*!query!=![[[database!viewNamed:@"byDate"]!query]!asLiveQuery];!!!!!query.descending!=!YES;!

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

@property(nonatomic,!strong)!IBOutlet!UITableView!*tableView;!@property(nonatomic,!strong)!IBOutlet!CBLUITableSource*!dataSource;

RootViewController.h:41

29

Page 37: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc. 37©2015&Couchbase&Inc.

LiveQuery

Querying+a+View

30

key value docID

“2013D03D12” “taxes” “doc17”

“2013D09D30” “call)mom” “doc62”

“2013D10D17” “cat)food” “doc82”

“2013D10D17” “tea)bags” “doc83”

“2013D10D22” “upgrade” “doc90”

index

} Query QueryRowQueryRowQueryRow

.limit&=&3&

.offset&=&…&

.reverse&=&…&

.startKey&=&…&

.endKey&=&…

"

"

Page 38: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc. 38©2015&Couchbase&Inc.

LiveQuery+Driving+A+GUI+Table

31

LiveQuery

QueryCBLUITableN

Source

UITableView

Your+Controller

! data source

delegate

Note:&CBLUITableSource&is&iOSJonly

Page 39: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc. 39©2015&Couchbase&Inc.

LiveQuery+Driving+A+GUI+Table

32

Page 40: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc. 40©2015&Couchbase&Inc.

Driving+the+Table+from+a+View+QueryRootViewController.m:101

!!!!//"Create"a"query"sorted"by"descending"date,"i.e."newest"items"first:!!!!!CBLLiveQuery*!query!=![[[database!viewNamed:@"byDate"]!query]!asLiveQuery];!!!!!query.descending!=!YES;!

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

@property(nonatomic,!strong)!IBOutlet!UITableView!*tableView;!@property(nonatomic,!strong)!IBOutlet!CBLUITableSource*!dataSource;

RootViewController.h:41

33

Page 41: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc. 41©2015&Couchbase&Inc.

Displaying+Table+CellsDemoAppDelegate.m:131W!(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!}

34

Called by the CBLUITableSource when it’s told to display a cell.

Page 42: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc. 42©2015&Couchbase&Inc.

Responding+To+TapsDemoAppDelegate.m:131

W!(void)tableView:(UITableView!*)tableView!!!!!!!!!!!didSelectRowAtIndexPath:(NSIndexPath!*)indexPath!{!!!!!//"Ask"CBLUITableSource"for"the"corresponding"query"row,"and"get"its"document:!!!!!CBLQueryRow!*row!=![self.dataSource!rowAtIndex:indexPath.row];!!!!!CBLDocument!*doc!=!row.document;!

!!!!//"Toggle"the"document's"'checked'"property:!!!!!NSMutableDictionary!*docContent!=![doc.properties!mutableCopy];!!!!!BOOL!wasChecked!=![docContent[@"check"]!boolValue];!!!!!docContent[@"check"]!=!@(!wasChecked);!

!!!!//"Save"changes:!!!!!NSError*!error;!!!!!if!(![doc.currentRevision!putProperties:!docContent!error:!&error])!{!!!!!!!!![self!showErrorAlert:!@"Failed!to!update!item"!forError:!error];!!!!!}!}!

35

Called by the UITableView itself

Page 43: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc. 43©2015&Couchbase&Inc.

Change+Notifications

▪ Three&types:&▪DatabaseChanged:&Any&document&updated&▪DocumentChanged:&A&specific&document&updated&▪ LiveQuery:&Change&in&query&result&set&▪ Enables&reactive&programming

ControllerModel&

(Database)GUI&View

User&event Update&doc

DocumentChangedRedraw

36

Page 44: Mobile workshop: Couchbase lite in-depth

Index

Page 45: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc.

Map/Reduce  Index

45

@interface List : CBLModel

@property NSString *title;

+ (CBLQuery*) queryListsInDatabase: (CBLDatabase*)db;

@end

@implementation Task @dynamic title;

+ (CBLQuery*) queryListsInDatabase: (CBLDatabase*)db { // ... }

@end

Page 46: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc.

Map/Reduce  Index

46

+ (CBLQuery*) queryListsInDatabase: (CBLDatabase*)db {

}

Page 47: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc.

Map/Reduce  Index

47

+ (CBLQuery*) queryListsInDatabase: (CBLDatabase*)db { CBLView* view = [db viewNamed: @"lists"]; if (!view.mapBlock) {

} return [view createQuery]; }

Page 48: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc.

Map/Reduce  Index

48

+ (CBLQuery*) queryListsInDatabase: (CBLDatabase*)db { CBLView* view = [db viewNamed: @"lists"]; if (!view.mapBlock) { [view setMapBlock: MAPBLOCK({

}) reduceBlock: nil version: @"1"]; } return [view createQuery]; }

Page 49: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc.

Map/Reduce  Index

49

+ (CBLQuery*) queryListsInDatabase: (CBLDatabase*)db { CBLView* view = [db viewNamed: @"lists"]; if (!view.mapBlock) { [view setMapBlock: MAPBLOCK({ if ([doc[@"type"] isEqualToString:@"list"]) emit(doc[@"title"], nil); }) reduceBlock: nil version: @"1"]; } return [view createQuery]; }

Page 50: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc.

Map/Reduce  Index

50

- (CBLQuery*) queryTasks { CBLView* view = [self.document.database viewNamed: @"tasksByDate"]; if (!view.mapBlock) { [view setMapBlock: MAPBLOCK({ if ([doc[@"type"] isEqualToString: @"task"]) { } }) reduceBlock: nil version: @"4"]; } CBLQuery* query = [view createQuery]; return query; }

Page 51: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc.

Map/Reduce  Index

51

- (CBLQuery*) queryTasks { CBLView* view = [self.document.database viewNamed: @"tasksByDate"]; if (!view.mapBlock) { [view setMapBlock: MAPBLOCK({ if ([doc[@"type"] isEqualToString: @"task"]) { id date = doc[@"created_at"]; NSString* listID = doc[@"list_id"]; emit(@[listID, date], doc); } }) reduceBlock: nil version: @"4"]; } CBLQuery* query = [view createQuery]; return query; }

Page 52: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc.

Map/Reduce  Index

52

- (CBLQuery*) queryTasks { CBLView* view = [self.document.database viewNamed: @"tasksByDate"]; if (!view.mapBlock) { [view setMapBlock: MAPBLOCK({ if ([doc[@"type"] isEqualToString: @"task"]) { id date = doc[@"created_at"]; NSString* listID = doc[@"list_id"]; emit(@[listID, date], doc); } }) reduceBlock: nil version: @"4"]; } CBLQuery* query = [view createQuery]; NSString* listId = self.document.documentID; return query; }

Page 53: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc.

Map/Reduce  Index

53

- (CBLQuery*) queryTasks { CBLView* view = [self.document.database viewNamed: @"tasksByDate"]; if (!view.mapBlock) { [view setMapBlock: MAPBLOCK({ if ([doc[@"type"] isEqualToString: @"task"]) { id date = doc[@"created_at"]; NSString* listID = doc[@"list_id"]; emit(@[listID, date], doc); } }) reduceBlock: nil version: @"4"]; } CBLQuery* query = [view createQuery]; NSString* listId = self.document.documentID; query.startKey = @[listId]; query.endKey = @[listId, @{}]; return query; }

Page 54: Mobile workshop: Couchbase lite in-depth

©2015  Couchbase  Inc. ‹#›

Page 55: Mobile workshop: Couchbase lite in-depth

Query

Page 56: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc.

Query

56

Query query = database.getView("tasksByDate").createQuery();

QueryEnumerator result = query.run();for (Iterator<QueryRow> it = result; it.hasNext(); ) { // do something}

Page 57: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc.

Query

57

LiveQuery liveQuery = database.getView("tasksByDate").createQuery().toLiveQuery();

Page 58: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc.

Query

58

LiveQuery liveQuery = database.getView("tasksByDate").createQuery().toLiveQuery();liveQuery.addChangeListener(new LiveQuery.ChangeListener() { @Override public void changed(LiveQuery.ChangeEvent event) { // update the UI } });

Page 59: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc.

Query

59

Page 60: Mobile workshop: Couchbase lite in-depth

©2015  Couchbase  Inc. ‹#›

Page 61: Mobile workshop: Couchbase lite in-depth

Attachments

Page 62: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc.

Attachments

62

protected void onActivityResult(int requestCode, int resultCode, Intent data){ if (requestCode == REQUEST_CODE && resultCode == Activity.RESULT_OK) { InputStream stream = getContentResolver().openInputStream(data.getData()); }}

Page 63: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc.

Attachments

63

protected void onActivityResult(int requestCode, int resultCode, Intent data){ if (requestCode == REQUEST_CODE && resultCode == Activity.RESULT_OK) { InputStream stream = getContentResolver().openInputStream(data.getData()); Document document = database.getDocument("task-123"); }}

Page 64: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc.

Attachments

64

protected void onActivityResult(int requestCode, int resultCode, Intent data){ if (requestCode == REQUEST_CODE && resultCode == Activity.RESULT_OK) { InputStream stream = getContentResolver().openInputStream(data.getData()); Document document = database.getDocument("task-123"); UnsavedRevision newRevision = document.getCurrentRevision().createRevision(); }}

Page 65: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc.

Attachments

65

protected void onActivityResult(int requestCode, int resultCode, Intent data){ if (requestCode == REQUEST_CODE && resultCode == Activity.RESULT_OK) { InputStream stream = getContentResolver().openInputStream(data.getData()); Document document = database.getDocument("task-123"); UnsavedRevision newRevision = document.getCurrentRevision().createRevision(); newRevision.setAttachment("photo.jpg", "image/jpeg", stream); }}

Page 66: Mobile workshop: Couchbase lite in-depth

©2014  Couchbase  Inc.

Attachments

66

protected void onActivityResult(int requestCode, int resultCode, Intent data){ if (requestCode == REQUEST_CODE && resultCode == Activity.RESULT_OK) { InputStream stream = getContentResolver().openInputStream(data.getData()); Document document = database.getDocument("task-123"); UnsavedRevision newRevision = document.getCurrentRevision().createRevision(); newRevision.setAttachment("photo.jpg", "image/jpeg", stream); newRevision.save(); }}

Page 67: Mobile workshop: Couchbase lite in-depth

©2015  Couchbase  Inc. ‹#›

Page 68: Mobile workshop: Couchbase lite in-depth

©2015  Couchbase  Inc. ‹#›

Page 69: Mobile workshop: Couchbase lite in-depth

©2015  Couchbase  Inc. ‹#›

http://bit.ly/1KKiA8g

Page 70: Mobile workshop: Couchbase lite in-depth

©2015  Couchbase  Inc. ‹#›

http://bit.ly/1FrUJn0

Page 71: Mobile workshop: Couchbase lite in-depth

iOS  branch:  worhsop/start  

Android  branch:  workshop/initial_state