Post on 03-Mar-2017
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
@BradleyHolthttps://github.com/cloudhead/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/>
@BradleyHolthttps://github.com/cloudhead/http-console
http-console
http://127.0.0.1:5984/> GET /
@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://127.0.0.1:5984/>
@BradleyHolthttps://github.com/cloudhead/http-console
http-console
http://127.0.0.1:5984/> .q
@BradleyHolthttps://github.com/cloudhead/http-console
http-console
$ http-console https://bradley-holt.cloudant.com
@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/>
@BradleyHolthttps://github.com/cloudhead/http-console
http-console
https://bradley-holt.cloudant.com:443/> GET /
@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
http-console
https://bradley-holt.cloudant.com:443/>
@BradleyHolthttps://github.com/cloudhead/http-console
http-console
https://bradley-holt.cloudant.com:443/> .q
@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