CouchDB Day NYC 2017: Introduction to CouchDB 2.0

Post on 03-Mar-2017

45 views 8 download

Transcript of CouchDB Day NYC 2017: Introduction to CouchDB 2.0

Apache CouchDB Developer Day

Bradley Holt, Developer AdvocateThursday, February 9, 2017

Introducing Apache CouchDB 2.0

@BradleyHolt

@BradleyHolt

IBM Cloud Data Services

Open for DataA comprehensive portfolio of open source data services

What is Apache CouchDB?

Document DatabaseApache CouchDB is a JSON document database

HTTP APIApache CouchDB is accessed through an HTTP API

@BradleyHolt

GET /

GET /db/docPOST /db

DELETE /db/docPUT /db/doc

PUT /db

Peer-to-Peer Replication

@BradleyHolt

Cloudant SyncCouchDB PouchDB

CouchDB Replication Protocol

CouchDB

What's new in CouchDB 2.0?

CouchDB 1.x: Standalone

@BradleyHolt

CouchDB

CouchDB 2.0: Clusterered

@BradleyHolt

CouchDBnode1

CouchDBnode2

CouchDBnode3

haproxy

Shards and Replicas

q=8– Number of shards– One or more shards per node– Cannot have more nodes than shards

r=2– Read quorum

w=2– Write quorum

n=3– Number of replicas of every document

@BradleyHolt

CouchDBnode1

CouchDBnode2

CouchDBnode3

Mango

Declarative indexes MongoDB-style query language You can still use map/reduce views

@BradleyHolt

couch_peruser

@BradleyHolt

userdb-51d055

userdb-d76846userdb-905cec

userdb-adc95b

userdb-c082f2

userdb-730bba

userdb-c3d3e5

userdb-da3d25

userdb-a1ec1f

userdb-85bcfe

userdb-85a327userdb-9b9aba

What else is new?

Improved database compaction Faster index updates New _bulk_get endpoint for

optimized replication View-based filters in _changes feed Filter _changes feed with _doc_ids _all_docs and _changes will

support attachments=true

@BradleyHolt

Installing CouchDB 2.0

Apache CouchDB 2.0 Sandbox ClusterTry Apache CouchDB 2.0 on an IBM Cloudant sandbox cluster

@BradleyHolt

http-console

http-console

$ npm install http-console -g$ http-console 127.0.0.1:5984

@BradleyHolthttps://github.com/cloudhead/http-console

http-console

$ npm install http-console -g$ http-console 127.0.0.1:5984> http-console 0.6.3> Welcome, enter .help if you're lost.> Connecting to 127.0.0.1 on port 5984.

@BradleyHolthttps://github.com/cloudhead/http-console

http-console

http://127.0.0.1:5984/> GET /HTTP/1.1 200 OKContent-Type: text/plain; charset=utf-8

{ couchdb: 'Welcome', version: '9afa6a0', vendor: { name: 'The Apache Software Foundation' }}

@BradleyHolthttps://github.com/cloudhead/http-console

http-console

$ http-console https://bradley-holt.cloudant.com> http-console 0.6.3> Welcome, enter .help if you're lost.> Connecting to bradley-holt.cloudant.com on port 443.

@BradleyHolthttps://github.com/cloudhead/http-console

http-console

https://bradley-holt.cloudant.com:443/> GET /HTTP/1.1 200 OKContent-Type: application/json

{ couchdb: 'Welcome', version: '9d28c57', vendor: { name: 'IBM Cloudant', version: '5331', variant: 'paas' }, features: [ 'geo' ]}

@BradleyHolthttps://github.com/cloudhead/http-console

Exploring the CouchDB API

Connecting to CouchDB 2.0

$ http-console root:passw0rd@127.0.0.1:5984 --json

@BradleyHolt

Connecting to CouchDB 2.0

$ http-console root:passw0rd@127.0.0.1:5984 --json> http-console 0.6.3> Welcome, enter .help if you're lost.> Connecting to 127.0.0.1 on port 5984.

@BradleyHolt

Connecting to IBM Cloudant

$ http-console https://bradley-holt:passw0rd@bradley-holt.cloudant.com --json

@BradleyHolt

Connecting to IBM Cloudant

$ http-console https://bradley-holt:passw0rd@bradley-holt.cloudant.com --json> http-console 0.6.3> Welcome, enter .help if you're lost.> Connecting to bradley-holt.cloudant.com on port 443.

@BradleyHolt

Request Headers

/>

@BradleyHolt

Request Headers

/> .headers

@BradleyHolt

Request Headers

/> .headersAccept: application/jsonContent-Type: application/jsonAuthorization: Basic cm9vdDorMi95N3Y2aA==Host: 127.0.0.1

@BradleyHolt

PUT a Database

/>

@BradleyHolt

PUT a Database

/> PUT /kittens

@BradleyHolt

PUT a Database

/> PUT /kittens...

@BradleyHolt

PUT a Database

/> PUT /kittens... HTTP/1.1 201 CreatedContent-Type: application/jsonLocation: http://127.0.0.1/kittens

{ ok: true }

@BradleyHolt

PUT a Database Again

/>

@BradleyHolt

PUT a Database Again

/> PUT /kittens

@BradleyHolt

PUT a Database Again

/> PUT /kittens...

@BradleyHolt

PUT a Database Again

/> PUT /kittens... HTTP/1.1 412 Precondition FailedContent-Type: application/json

{ error: 'file_exists', reason: 'The database could not be created, the file already exists.' }

@BradleyHolt

POST a Document

/>

@BradleyHolt

POST a Document

/> /kittens

@BradleyHolt

POST a Document

/kittens>

@BradleyHolt

POST a Document

/kittens> POST /

@BradleyHolt

POST a Document

/kittens> POST /...

@BradleyHolt

POST a Document

/kittens> POST /... { "_id": "mittens", "age_weeks": 10, "weight_kilograms": 0.997 }

@BradleyHolt

POST a Document

/kittens> POST /... { "_id": "mittens", "age_weeks": 10, "weight_kilograms": 0.997 }HTTP/1.1 201 CreatedContent-Type: application/jsonLocation: http://127.0.0.1/kittens/mittens

{ ok: true, id: 'mittens', rev: '1-e665a40d9ea9711c983e907f0b0b6e8a'}

@BradleyHolt

GET All Documents

/kittens>

@BradleyHolt

GET All Documents

/kittens> GET /_all_docs

@BradleyHolt

GET All Documents

/kittens> GET /_all_docsHTTP/1.1 200 OKContent-Type: application/jsonEtag: "92afa0f309a9fd9f140cd31ff5000b5c"

{ total_rows: 1, offset: 0, rows: [ { id: 'mittens', key: 'mittens', value: { rev: '1-e665a40d9ea9711c983e907f0b0b6e8a' } } ]}

@BradleyHolt

GET a Document

/kittens>

@BradleyHolt

GET a Document

/kittens> GET /mittens

@BradleyHolt

GET a Document

/kittens> GET /mittensHTTP/1.1 200 OKContent-Type: application/jsonEtag: "1-e665a40d9ea9711c983e907f0b0b6e8a"

{ _id: 'mittens', _rev: '1-e665a40d9ea9711c983e907f0b0b6e8a', age_weeks: 10, weight_kilograms: 0.997}

@BradleyHolt

PUT an Attachment

/kittens>

@BradleyHolt

PUT an Attachment

/kittens> .headers

@BradleyHolt

PUT an Attachment

/kittens> .headersAccept: application/jsonContent-Type: application/jsonAuthorization: Basic cm9vdDorMi95N3Y2aA==Host: 127.0.0.1

@BradleyHolt

PUT an Attachment

/kittens> .headersAccept: application/jsonContent-Type: application/jsonAuthorization: Basic cm9vdDorMi95N3Y2aA==Host: 127.0.0.1/kittens> Content-Type: image/gif

@BradleyHolt

PUT an Attachment

/kittens>

@BradleyHolt

PUT an Attachment

/kittens> PUT /mittens/photo?rev=1-e665a40d9ea9711c983e907f0b0b6e8a

@BradleyHolt

PUT an Attachment

/kittens> PUT /mittens/photo?rev=1-e665a40d9ea9711c983e907f0b0b6e8a...

@BradleyHolt

PUT an Attachment

/kittens> PUT /mittens/photo?rev=1-e665a40d9ea9711c983e907f0b0b6e8a... R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=

@BradleyHolt

PUT an Attachment

/kittens> PUT /mittens/photo?rev=1-e665a40d9ea9711c983e907f0b0b6e8a... R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=HTTP/1.1 201 CreatedContent-Type: application/jsonLocation: http://127.0.0.1/kittens/mittens/photo

{ ok: true, id: 'mittens', rev: '2-d858e51453a5785bafe517b7eddc5a98'}

@BradleyHolt

PUT an Attachment

/kittens> PUT /mittens/photo?rev=1-e665a40d9ea9711c983e907f0b0b6e8a... R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=HTTP/1.1 201 CreatedContent-Type: application/jsonLocation: http://127.0.0.1/kittens/mittens/photo

{ ok: true, id: 'mittens', rev: '2-d858e51453a5785bafe517b7eddc5a98'}/kittens>

@BradleyHolt

PUT an Attachment

/kittens> PUT /mittens/photo?rev=1-e665a40d9ea9711c983e907f0b0b6e8a... R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=HTTP/1.1 201 CreatedContent-Type: application/jsonLocation: http://127.0.0.1/kittens/mittens/photo

{ ok: true, id: 'mittens', rev: '2-d858e51453a5785bafe517b7eddc5a98'}/kittens> Content-Type: application/json

@BradleyHolt

GET an Attachment

/kittens>

@BradleyHolt

GET an Attachment

/kittens> GET /mittens/photo

@BradleyHolt

GET an Attachment

/kittens> GET /mittens/photoHTTP/1.1 200 OKContent-Type: image/gifEtag: "UsqjdPnY6ApD2ENFOglFHg=="

R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=

@BradleyHolt

Conditional Caching

/kittens>

@BradleyHolt

Conditional Caching

/kittens> If-None-Match: "UsqjdPnY6ApD2ENFOglFHg=="

@BradleyHolt

Conditional Caching

/kittens> If-None-Match: "UsqjdPnY6ApD2ENFOglFHg=="/kittens>

@BradleyHolt

Conditional Caching

/kittens> If-None-Match: "UsqjdPnY6ApD2ENFOglFHg=="/kittens> GET /mittens/photo

@BradleyHolt

Conditional Caching

/kittens> If-None-Match: "UsqjdPnY6ApD2ENFOglFHg=="/kittens> GET /mittens/photoHTTP/1.1 304 Not Modified

@BradleyHolt

Conditional Caching

/kittens> If-None-Match: "UsqjdPnY6ApD2ENFOglFHg=="/kittens> GET /mittens/photoHTTP/1.1 304 Not Modified

/kittens>

@BradleyHolt

Conditional Caching

/kittens> If-None-Match: "UsqjdPnY6ApD2ENFOglFHg=="/kittens> GET /mittens/photoHTTP/1.1 304 Not Modified

/kittens> If-None-Match:

@BradleyHolt

DELETE a Document

/kittens>

@BradleyHolt

DELETE a Document

/kittens> DELETE /mittens

@BradleyHolt

DELETE a Document

/kittens> DELETE /mittensHTTP/1.1 409 ConflictContent-Type: application/json

{ error: 'conflict', reason: 'Document update conflict.' }

@BradleyHolt

DELETE a Document

/kittens>

@BradleyHolt

DELETE a Document

/kittens> HEAD /mittens

@BradleyHolt

DELETE a Document

/kittens> HEAD /mittensHTTP/1.1 200 OKEtag: "2-d858e51453a5785bafe517b7eddc5a98"

@BradleyHolt

DELETE a Document

/kittens>

@BradleyHolt

DELETE a Document

/kittens> If-Match: "2-d858e51453a5785bafe517b7eddc5a98"

@BradleyHolt

DELETE a Document

/kittens> If-Match: "2-d858e51453a5785bafe517b7eddc5a98"/kittens>

@BradleyHolt

DELETE a Document

/kittens> If-Match: "2-d858e51453a5785bafe517b7eddc5a98"/kittens> DELETE /mittens

@BradleyHolt

DELETE a Document

/kittens> If-Match: "2-d858e51453a5785bafe517b7eddc5a98"/kittens> DELETE /mittensHTTP/1.1 200 OKContent-Type: application/json

{ ok: true, id: 'mittens', rev: '3-d0780627ddff7a7f536fe273100cec41'}

@BradleyHolt

DELETE a Document

/kittens> If-Match: "2-d858e51453a5785bafe517b7eddc5a98"/kittens> DELETE /mittensHTTP/1.1 200 OKContent-Type: application/json

{ ok: true, id: 'mittens', rev: '3-d0780627ddff7a7f536fe273100cec41'}/kittens>

@BradleyHolt

DELETE a Document

/kittens> If-Match: "2-d858e51453a5785bafe517b7eddc5a98"/kittens> DELETE /mittensHTTP/1.1 200 OKContent-Type: application/json

{ ok: true, id: 'mittens', rev: '3-d0780627ddff7a7f536fe273100cec41'}/kittens> If-Match:

@BradleyHolt

Replication

/kittens>

@BradleyHolt

Replication

/kittens> ..

@BradleyHolt

Replication

/kittens> ../>

@BradleyHolt

Replication

/kittens> ../> DELETE /kittens

@BradleyHolt

Replication

/kittens> ../> DELETE /kittensHTTP/1.1 200 OKContent-Type: application/json

{ ok: true }

@BradleyHolt

Replication

/>

@BradleyHolt

Replication

/> POST /_replicate

@BradleyHolt

Replication

/> POST /_replicate...

@BradleyHolt

Replication

/> POST /_replicate... { "create_target": true, "source": "https://bradley-holt.cloudant.com/kittens", "target": "kittens" }

@BradleyHolt

Replication

/> POST /_replicate... { "create_target": true, "source": "https://bradley-holt.cloudant.com/kittens", "target": "kittens" }HTTP/1.1 200 OKContent-Type: application/json

{ ok: true, session_id: '9f7bd286a0001ece5bf0bf65dd83c5ab', source_last_seq: '5-g1AAAAFDeJzLYWBgYMlgTmGQT0lKzi9KdUhJMtVLykxPyilN1UvOyS9NScwr0ctLLckBKmRKZEiy____f1YiA6oWQ9xakhyAZFI9SFcGcyJzLpDHbplmZmxkaULYBKIdlscCJBkagBTQov2kuA-i8wBEJ9iNTGA3mhoampmnGBA2JQsA1LtoyA', …}

@BradleyHolt

Mango

/>

@BradleyHolt

Mango

/> /kittens

@BradleyHolt

Mango

/kittens>

@BradleyHolt

Mango

/kittens> POST /_index

@BradleyHolt

Mango

/kittens> POST /_index...

@BradleyHolt

Mango

/kittens> POST /_index... { "index": { "fields": [ "age_weeks", "weight_kilograms" ] } }

@BradleyHolt

Mango

/kittens> POST /_index... { "index": { "fields": [ "age_weeks", "weight_kilograms" ] } }HTTP/1.1 200 OKContent-Type: application/json

{ result: 'created', id: '_design/e19dde7f518129a966ebe072edc66be88d54e694', name: 'e19dde7f518129a966ebe072edc66be88d54e694'}

@BradleyHolt

@BradleyHolt

Mango

/kittens>

@BradleyHolt

Mango

/kittens> POST /_find

@BradleyHolt

Mango

/kittens> POST /_find...

@BradleyHolt

Mango

/kittens> POST /_find... { "selector": { "age_weeks": { "$gte": 7, "$lte": 10 } }, "fields": [ "_id", "age_weeks" ] }

@BradleyHolt

Mango

/kittens> POST /_find... { "selector": { "age_weeks": { "$gte": 7, "$lte": 10 } }, "fields": [ "_id", "age_weeks" ] }HTTP/1.1 200 OKContent-Type: application/json

{ docs: [ { _id: 'tiger', age_weeks: 7 }, { _id: 'daisy', age_weeks: 9 }, { _id: 'mittens', age_weeks: 10 } ]}

@BradleyHolt

@BradleyHolt

Mango

/kittens>

@BradleyHolt

Mango

/kittens> POST /_find

@BradleyHolt

Mango

/kittens> POST /_find...

@BradleyHolt

Mango

/kittens> POST /_find... { "selector": { "age_weeks": { "$gte": 0 }, "weight_kilograms": { "$gte": 0.5, "$lte": 1 } }, "fields": [ "_id", "weight_kilograms" ] }

@BradleyHolt

Mango

/kittens> POST /_find... { "selector": { "age_weeks": { "$gte": 0 }, "weight_kilograms": { "$gte": 0.5, "$lte": 1 } }, "fields": [ "_id", "weight_kilograms" ] }HTTP/1.1 200 OKContent-Type: application/json

{ docs: [ { _id: 'tiger', weight_kilograms: 0.726 }, { _id: 'daisy', weight_kilograms: 0.816 }, { _id: 'mittens', weight_kilograms: 0.997 } ]}

@BradleyHolt

@BradleyHolt

Contributing

Offline First

Offline First

Lack of connectivity is not an error condition.

Cloudant Sync

Cloudant FoodTracker

Cloudant FoodTracker

Cloudant Location Tracker

Offline Camp BerlinApril 28th - May 1st, Berlin, Germany

offlinefirst.org/camp

Image Credits

paper by malik, on Flickr <https://flic.kr/p/aZjTXv> person by Tim Morgan, on Flickr <https://flic.kr/p/7DSF5> database by Tim Morgan, on Flickr <https://flic.kr/p/7DUk5> gear by Tim Morgan, on Flickr <https://flic.kr/p/7DSF1> Mango with section on a white background by bangdoll, on Flickr <https://flic.kr/p/9CBP2h>

@BradleyHolt

Questions?

@BradleyHolt