Upgrade to Pro — share decks privately, control downloads, hide ads and more …

CouchDB : NoSQL for Scalable Applications

CouchDB : NoSQL for Scalable Applications

Avatar for Lorna Mitchell

Lorna Mitchell

May 24, 2017
Tweet

More Decks by Lorna Mitchell

Other Decks in Technology

Transcript

  1. CouchDB Cluster Of Unreliable Commodity Hardware • HTTP API •

    JSON data format • MapReduce views in JavaScript • Mango is JSON-format also CouchDB 2.0 has clustering and sharding features @lornajane
  2. CouchDB HTTP API Hello, CouchDB ~ $ curl http://localhost:5984 {"couchdb":"Welcome","version":"2.0.0",

    "vendor":{"name":"The Apache Software Foundation"}} List databases ~ $ curl http://localhost:5984/_all_dbs [] @lornajane
  3. CouchDB HTTP API New database ~ $ curl -X PUT

    http://localhost:5984/shopping {"ok":true} List databases again ~ $ curl http://localhost:5984/_all_dbs ["shopping"] @lornajane
  4. Curl and Not-Curl • love curl? (https://curl.haxx.se/) • try jq

    (https://stedolan.github.io/jq/) • hate curl? Try one of these • http-console https://github.com/cloudhead/http-console • HTTPie https://httpie.org/ • Postman https://www.getpostman.com/ @lornajane
  5. Try http-console Connect: $ http-console http://localhost:5984 Set database in path

    (to avoid typing it lots): http://localhost:5984> /shopping Set JSON header: http://localhost:5984/shopping> Content-Type: application/json @lornajane
  6. Try http-console Create item: http://localhost:5984/shopping> PUT /hat ... {"colour": "white"}

    HTTP/1.1 201 Created Location: http://localhost/shopping/hat Etag: "1-12cb52ad7565b6248c4dbe09f1377e2b" { ok: true, id: 'hat', rev: '1-12cb52ad7565b6248c4dbe09f1377e2b' } @lornajane
  7. Try http-console Update item: http://localhost:5984/shopping> PUT /hat ... {"colour": "blue"}

    HTTP/1.1 409 Conflict { error: 'conflict', reason: 'Document update conflict.' } To update, include the revision ... @lornajane
  8. Try http-console Update item: http://localhost:5984/shopping> PUT /hat ... {"_rev": "1-12cb52ad7565b6248c4dbe09f1377e2b",

    "colour": "blue HTTP/1.1 201 Created Location: http://localhost/shopping/hat Etag: "2-15b01d3c5cd2ed475e6ce4cf84b51990" { ok: true, id: 'hat', rev: '2-15b01d3c5cd2ed475e6ce4cf84b51990' } @lornajane
  9. Replication • Replication can be in either direction - or

    both • Can be one-off, or continuous • Other CouchDB-compatible storage also exists • e.g. PouchDB, a JavaScript implementation @lornajane
  10. Conflicts Change docs in both places, replicate again: 87bf-bluemix.cloudant.com:443/shopping> GET

    /hat?conflicts=true { _id: 'hat', _rev: '4-ecbc38075f9a8535c123e523519613b9', colour: 'green', in_stock: 1, _conflicts: [ '3-0bb689d59034fb769d99dcf697ae2de7' ] } CouchDB will always choose the same "winning" doc @lornajane
  11. Conflicts Fetch the "losing" doc(s) with ?rev= parameter 87bf-bluemix.cloudant.com:443/shopping> GET

    /hat?rev=3-0bb689d5903 { _id: 'hat', _rev: '3-0bb689d59034fb769d99dcf697ae2de7', colour: 'blue', size: 'L' } CouchDB doesn't store old revisions forever @lornajane
  12. Mango: CouchDB Queries Mango is a mongo-like query language, useful

    for ad-hoc querying It is a JSON structure containing: • Selector: the criteria to match records on • Fields: which fields to return • Sort: what order you'd like that in (use with Skip) • Limit: how many records (default = 25) @lornajane
  13. Mango: Example Query Use a query like this with the

    _find endpoint { "selector": { "Year": {"$eq": "2012"} }, "fields": ["Quarter", "Product line"], "limit": 5 } @lornajane
  14. Mango: Example Query $ curl -X POST -H Content-Type:application/json \

    http://localhost:5984/products/_find --data @mango.json {"warning":"no matching index found, create an index to optimize q "docs":[ {"Quarter":"Q1 2012","Product line":"Mountaineering Equipment"}, {"Quarter":"Q1 2012","Product line":"Mountaineering Equipment"}, {"Quarter":"Q1 2012","Product line":"Mountaineering Equipment"}, {"Quarter":"Q1 2012","Product line":"Mountaineering Equipment"}, {"Quarter":"Q1 2012","Product line":"Mountaineering Equipment"} ]} @lornajane
  15. Mango: Indexes Describe the index in JSON, then use the

    _index endpoint { "index": { "fields": ["Year"] }, "name": "Year" } @lornajane
  16. Mango: Indexes $ curl -X POST -H Content-Type:application/json \ http://localhost:5984/products/_index

    --data @index.json { "result": "created", "id": "_design/e9b54f2ac34b8823ccbe8aaf6f406d464f50f521", "name": "Year" } Check which indexes are used by putting _explain where the _find normally goes! @lornajane
  17. Views • Written in Javascript • Use MapReduce • The

    map results are stored • Can be used either for filtering, or for aggregation • Geospatial features also available (not in today's talk, sorry) @lornajane
  18. MapReduce Primer: Map • Examine each document, "emit" 0+ keys/value

    pairs • Scales well because each document is independent • To filter a collection of documents, use map step only @lornajane
  19. MapReduce Primer: Reduce • "Reduce" values in batches with the

    same key • CouchDB has useful built in functions for most things • Use reduce step when you want aggregate data • (SQL equivalent: a query with GROUP BY) @lornajane
  20. Views Example function (doc) { emit(doc.year, 1); } Reduce: _COUNT

    ... no really, this is a view URL: http://localhost:5984/products/_design/myview/_view/year @lornajane
  21. Views Example Find records sorted by year: ?include_docs=true&reduce=false Find records

    with a specific year: ?key="2012"&include_docs=true&reduce=false Count number of records per year (uses reduce): ?group=true @lornajane
  22. Composite Keys We can emit an array as the key.

    e.g. turn the "Quarter" field from 2012 Q3 to [2012, 3] function (doc) { year = doc.Quarter.substring(3); quarter = doc.Quarter.substring(1,2); emit([year, quarter], null); } @lornajane
  23. PouchDB • https://pouchdb.com/ • A database that your client-side javascript

    can use • Can also sync to CouchDB (-compatible) databases • https://tinyurl.com/fauxton-pouchdb • UI for PouchDB in your browser @lornajane
  24. PouchDB in Action In index.html: <script src="/js/pouchdb-6.1.2.min.js"></script> <script src="/js/shopping.js"></script> shopping.js

    is where my client-side JavaScript lives Code is here: https://github.com/lornajane/robust-shopping-list @lornajane
  25. PouchDB: Replication var db = new PouchDB('shopping'); var remoteDB =

    new PouchDB('http://localhost:5984/shopping'); window.onload = function() { db.sync(remoteDB, { live: true, retry: true } ).on('change', function (change) { return getItemList().then(function (contents) { document.getElementById('itemList').innerHTML = conten }) }).on('active', function (info) { return getItemList().then(function (contents) { document.getElementById('itemList').innerHTML = conten }); }); @lornajane
  26. Questions? Resources: • https://lornajane.net • https://couchdb.apache.org/ • https://pouchdb.com/ • https://offlinefirst.org

    If you liked it, tweet: @CouchDB, @PouchDB and @IBMCloudant (and of course @austinphp and @lornajane) @lornajane