1.5. Getting Started
In this document, we’ll take a quick tour of CouchDB’s features.We’ll create our first document and experiment with CouchDB views.
1.5.1. All Systems Are Go!
We’ll have a very quick look at CouchDB’s bare-bones Application ProgrammingInterface (API) by using the command-line utility curl. Please note that thisis not the only way of talking to CouchDB. We will show you plenty morethroughout the rest of the documents. What’s interesting about curl is that itgives you control over raw HTTP requests, and you can see exactly what isgoing on “underneath the hood” of your database.
Make sure CouchDB is still running, and then do:
- curl http://127.0.0.1:5984/
This issues a GET request to your newly installed CouchDB instance.
The reply should look something like:
- {
- "couchdb": "Welcome",
- "version": "2.2.0",
- "git_sha":"2a16ec4",
- "features": [
- "pluggable-storage-engines",
- "scheduler"
- ],
- "vendor": {
- "name": "The Apache Software Foundation"
- }
- }
Not all that spectacular. CouchDB is saying “hello” with the running versionnumber.
Next, we can get a list of databases:
- curl -X GET http://127.0.0.1:5984/_all_dbs
All we added to the previous request is the _all_dbs string.
The response should look like:
- ["_global_changes","_replicator","_users"]
Note
In case this returns an empty Array for you, it means you haven’t finishedinstallation correctly. Please refer to Setup for furtherinformation on this.
Oh, that’s right, we didn’t create any databases yet! All we see is an emptylist.
Note
The curl command issues GET requests by default. You can issue POST requestsusing curl -X POST
. To make it easy to work with our terminal history,we usually use the -X
option even when issuing GET requests.If we want to send a POST next time, all we have to change is the method.
HTTP does a bit more under the hood than you can see in the examples here.If you’re interested in every last detail that goes over the wire,pass in the -v
option (e.g., curl -vX GET
), which will show youthe server curl tries to connect to, the request headers it sends,and response headers it receives back. Great for debugging!
Let’s create a database:
- curl -X PUT http://127.0.0.1:5984/baseball
CouchDB will reply with:
- {"ok":true}
Retrieving the list of databases again shows some useful results this time:
- curl -X GET http://127.0.0.1:5984/_all_dbs
- ["baseball"]
Note
We should mention JavaScript Object Notation (JSON) here, the data formatCouchDB speaks. JSON is a lightweight data interchange format based onJavaScript syntax. Because JSON is natively compatible with JavaScript, yourweb browser is an ideal client for CouchDB.
Brackets ([]
) represent ordered lists, and curly braces ({}
)represent key/value dictionaries. Keys must be strings, delimited by quotes("
), and values can be strings, numbers, booleans, lists, or key/valuedictionaries. For a more detailed description of JSON, see Appendix E, JSONPrimer.
Let’s create another database:
- curl -X PUT http://127.0.0.1:5984/baseball
CouchDB will reply with:
- {"error":"file_exists","reason":"The database could not be created,
- the file already exists."}
We already have a database with that name, so CouchDB will respond with anerror. Let’s try again with a different database name:
- curl -X PUT http://127.0.0.1:5984/plankton
CouchDB will reply with:
- {"ok":true}
Retrieving the list of databases yet again shows some useful results:
- curl -X GET http://127.0.0.1:5984/_all_dbs
CouchDB will respond with:
- ["baseball", "plankton"]
To round things off, let’s delete the second database:
- curl -X DELETE http://127.0.0.1:5984/plankton
CouchDB will reply with:
- {"ok":true}
The list of databases is now the same as it was before:
- curl -X GET http://127.0.0.1:5984/_all_dbs
CouchDB will respond with:
- ["baseball"]
For brevity, we’ll skip working with documents, as the next section covers adifferent and potentially easier way of working with CouchDB that shouldprovide experience with this. As we work through the example,keep in mind that “under the hood” everything is being done by theapplication exactly as you have been doing here manually.Everything is done using GET, PUT, POST, and DELETE with a URI.
1.5.2. Welcome to Fauxton
After having seen CouchDB’s raw API, let’s get our feet wet by playing withFauxton, the built-in administration interface. Fauxton provides full accessto all of CouchDB’s features and makes it easy to work with some of the morecomplex ideas involved. With Fauxton we can create and destroy databases; viewand edit documents; compose and run MapReduce views; and trigger replicationbetween databases.
To load Fauxton in your browser, visit:
- http://127.0.0.1:5984/_utils/
In later documents, we’ll focus on using CouchDB fromserver-side languages such as Ruby and Python. As such, this document is a greatopportunity to showcase an example of natively serving up a dynamic webapplication using nothing more than CouchDB’s integrated web server, somethingyou may wish to do with your own applications.
The first thing we should do with a fresh installation of CouchDB is run thetest suite to verify that everything is working properly. This assures usthat any problems we may run into aren’t due to bothersome issues with oursetup. By the same token, failures in the Fauxton test suite are a red flag,telling us to double-check our installation before attempting to use apotentially broken database server, saving us the confusion when nothingseems to be working quite like we expect!
To validate your installation, click on the Verify link on the left-handside, then press the green Verify Installation button. All tests shouldpass with a check mark. If any fail, re-check your installation steps.
1.5.3. Your First Database and Document
Creating a database in Fauxton is simple. From the overview page,click “Create Database.” When asked for a name, enter hello-world and clickthe Create button.
After your database has been created, Fauxton will display a list of all itsdocuments. This list will start out empty, so let’screate our first document. Click the plus sign next to “All Documents” andselect the “New Doc” link. CouchDB will generate a UUID for you.
For demoing purposes, having CouchDB assign a UUID is fine. When you writeyour first programs, we recommend assigning your own UUIDs. If you rely onthe server to generate the UUID and you end up making two POST requestsbecause the first POST request bombed out, you might generate two docs andnever find out about the first one because only the second one will bereported back. Generating your own UUIDs makes sure that you’ll never end upwith duplicate documents.
Fauxton will display the newly created document, with its _id field. To createa new field, simply use the editor to write valid JSON. Add a new field byappending a comma to the _id
value, then adding the text:
- "hello": "my new value"
Click the green Create Document button to finalize creating thedocument.
You can experiment with other JSON values; e.g., [1, 2, "c"]
or{"foo": "bar"}
.
You’ll notice that the document’s _rev has been added. We’ll go into more detailabout this in later documents, but for now, the important thing to note isthat _rev acts like a safety feature when saving a document. As long as youand CouchDB agree on the most recent _rev of a document, you can successfullysave your changes.
For clarity, you may want to display the contents of the document in the alldocument view. To enable this, from the upper-right corner of the window,select Options, then check the Include Docs option. Finally, press the RunQuery button. The full document should be displayed along with the _id
and _rev
values.
1.5.4. Running a Query Using MapReduce
Traditional relational databases allow you to run any queries you like aslong as your data is structured correctly. In contrast,CouchDB uses predefined map and reduce functions in a style known asMapReduce. These functions provide great flexibility because they can adaptto variations in document structure, and indexes for each document can becomputed independently and in parallel. The combination of a map and a reducefunction is called a view in CouchDB terminology.
For experienced relational database programmers, MapReduce can take somegetting used to. Rather than declaring which rows from which tables toinclude in a result set and depending on the database to determine the mostefficient way to run the query, reduce queries are based on simple rangerequests against the indexes generated by your map functions.
Map functions are called once with each document as the argument.The function can choose to skip the document altogether or emit one or moreview rows as key/value pairs. Map functions may not depend on any informationoutside of the document. This independence is what allows CouchDB views to begenerated incrementally and in parallel.
CouchDB views are stored as rows that are kept sorted by key. This makesretrieving data from a range of keys efficient even when there are thousandsor millions of rows. When writing CouchDB map functions,your primary goal is to build an index that stores related data under nearbykeys.
Before we can run an example MapReduce view, we’ll need some data to run iton. We’ll create documents carrying the price of various supermarket items asfound at different shops. Let’s create documents for apples, oranges,and bananas. (Allow CouchDB to generate the _id and _rev fields.) Use Fauxtonto create documents that have a final JSON structure that looks like this:
- {
- "_id": "00a271787f89c0ef2e10e88a0c0001f4",
- "_rev": "1-2628a75ac8c3abfffc8f6e30c9949fd6",
- "item": "apple",
- "prices": {
- "Fresh Mart": 1.59,
- "Price Max": 5.99,
- "Apples Express": 0.79
- }
- }
OK, now that that’s done, let’s create the document for oranges:
- {
- "_id": "00a271787f89c0ef2e10e88a0c0003f0",
- "_rev": "1-e9680c5d9a688b4ff8dd68549e8e072c",
- "item": "orange",
- "prices": {
- "Fresh Mart": 1.99,
- "Price Max": 3.19,
- "Citrus Circus": 1.09
- }
- }
And finally, the document for bananas:
- {
- "_id": "00a271787f89c0ef2e10e88a0c00048b",
- "_rev": "1-60e25d93dc12884676d037400a6fa189",
- "item": "banana",
- "prices": {
- "Fresh Mart": 1.99,
- "Price Max": 0.79,
- "Banana Montana": 4.22
- }
- }
Imagine we’re catering a big luncheon, but the client is very price-sensitive.To find the lowest prices, we’re going to create our first view,which shows each fruit sorted by price. Click “All Documents” to return to thehello-world overview, and then from the “All Documents” plus sign, click “NewView” to create a new view.
Name the design document _design/myDesignDoc
, and set the Index nameto prices
.
Edit the map function, on the right, so that it looks like the following:
- function(doc) {
- var shop, price, value;
- if (doc.item && doc.prices) {
- for (shop in doc.prices) {
- price = doc.prices[shop];
- value = [doc.item, shop];
- emit(price, value);
- }
- }
- }
This is a JavaScript function that CouchDB runs for each of our documents asit computes the view. We’ll leave the reduce function blank for the time being.
Click “Save Document and then Build Index” and you should see result rows,with the various items sorted by price. This map function could be even moreuseful if it grouped the items by type so that all the prices for bananas werenext to each other in the result set. CouchDB’s key sorting system allows anyvalid JSON object as a key. In this case, we’ll emit an array of [item, price]so that CouchDB groups by item type and price.
Let’s modify the view function (click the wrench icon next to the Views >prices Design Document on the left, then select Edit) so that it looks likethis:
- function(doc) {
- var shop, price, key;
- if (doc.item && doc.prices) {
- for (shop in doc.prices) {
- price = doc.prices[shop];
- key = [doc.item, price];
- emit(key, shop);
- }
- }
- }
Here, we first check that the document has the fields we want to use. CouchDBrecovers gracefully from a few isolated map function failures,but when a map function fails regularly (due to a missing required field orother JavaScript exception), CouchDB shuts off its indexing to prevent anyfurther resource usage. For this reason, it’s important to check for theexistence of any fields before you use them. In this case,our map function will skip the first “hello world” document we createdwithout emitting any rows or encountering any errors. The result of thisquery should now be displayed.
Once we know we’ve got a document with an item type and some prices,we iterate over the item’s prices and emit key/values pairs. The key is anarray of the item and the price, and forms the basis for CouchDB’s sortedindex. In this case, the value is the name of the shop where the item can befound for the listed price.
View rows are sorted by their keys – in this example, first by item,then by price. This method of complex sorting is at the heart of creatinguseful indexes with CouchDB.
MapReduce can be challenging, especially if you’ve spent years working withrelational databases. The important things to keep in mind are that mapfunctions give you an opportunity to sort your data using any key you choose,and that CouchDB’s design is focused on providing fast,efficient access to data within a range of keys.
1.5.5. Triggering Replication
Fauxton can trigger replication between two local databases,between a local and remote database, or even between two remote databases.We’ll show you how to replicate data from one local database to another,which is a simple way of making backups of your databases as we’re workingthrough the examples.
First we’ll need to create an empty database to be the target of replication.Return to the Databases overview and create a database calledhello-replication
. Now click “Replication” in the sidebar and choosehello-world as the source and hello-replication as the target. Click“Replicate” to replicate your database.
To view the result of your replication, click on the Databases tab again.You should see the hello-replication database has the same number of documentsas the hello-world database, and it should take up roughly the same size aswell.
Note
For larger databases, replication can take much longer. It is important toleave the browser window open while replication is taking place.As an alternative, you can trigger replication via curl or some other HTTPclient that can handle long-running connections. If your client closes theconnection before replication finishes, you’ll have to retrigger it.Luckily, CouchDB’s replication can take over from where it left offinstead of starting from scratch.
1.5.6. Wrapping Up
Now that you’ve seen most of Fauxton’s features, you’ll be prepared to dive inand inspect your data as we build our example application in the next fewdocuments. Fauxton’s pure JavaScript approach to managing CouchDB shows howit’s possible to build a fully featured web application using only CouchDB’sHTTP API and integrated web server.
But before we get there, we’ll have another look at CouchDB’s HTTP API – nowwith a magnifying glass. Let’s curl up on the couch and relax.