CouchDB, jcouchdb and map (in more detail)


I have already written a very first tutorial about jcouchdb and map. But for those used to write SELECT in SQL there a lot of things other than those simple queries.

Nevertheless, you should switch your mind since working with CouchDB map/reduce function will be a completely new paradigm and there are no magic recipes about how to convert SQL tables on CouchDB documents and SELECTS on map/reduce functions.

Example Database and create, update, query Views in CouchDb

First, I will refer you to the Database that I created as example here. Where I inserted some small documents with some few properties and the helper functions for creating / updating / querying views introduced here.

Limiting the number of results in jcouchdb

HelperFunctions.defineView(db, "sortedById",
                           "function(doc) { emit(doc._id, doc); }");
ViewResult result = db.queryView("views/sortedById",
                                 BaseDocument.class,
                                 new Options().limit(100),
                                 null);
// Check that we get 100 results
assertEquals(result.getRows().size(), 100);

In line 1-2 we define a map function that emits the identifier of the document  and the document itself. Then we call queryView (line 3) method asking for a document of type BaseDocument (line 4) and we introduce a new method in Options class called limit that allows you to specify the maximum number of document to retrieve.

Line 8 verifies that we actually get 100 documents.

NOTEViewResult contains a method name getTotalRows that returns the number of row that meet the condition BUT not the ones that have been retrieved.

One additional question is that map returns the results ordered by key (first argument of emit function) so, in the previous example, we got the results ordered by identifier.

Getting results ordered with jcouchdb

Consider the following code that defines a view for getting results ordered by date.

HelperFunctions.defineView(db,
                           "sortedByDate",
                           "function(doc) { emit(doc.date, doc); }");
ViewResult result = db.queryView("views/sortedByDate",
                                               BaseDocument.class,
                                               new Options().limit(100),
                                               null);
List rows = result.getRows();

// Check that we get 100 results
assertEquals(rows.size(), 100);

// Verify that they are actually sorted by date (key)
for (int i = 1; i < rows.size(); i++) {
    assertTrue(((String) rows.get(i - 1).getKey()).compareTo((String) rows.get(i).getKey()) }

As in the previous example we define a view (using our HelperFunctions) and then invoke Database queryView. We limit the number of results to 100 (line 6) and then in line 14-16 we iterate in results comparing that each date compared with previous is actually equal or greater.

NOTE: we can actually do this because we saved dates as YYYY-MM-DD.

Querying in jcouchdb for a key value that is in a set of values

Consider the same map function (sortedByDate) that in previous section and now we are going to use queryViewByKeys instead of queryView that includes an extra argument that is the list of values to match the key that we are looking for.

HelperFunctions.defineView(db, "sortedByDate", "function(doc) { emit(doc.date, doc); }");
List list = Arrays.asList("2012-01-01", "2012-01-02", "2012-01-03");

ViewResult result = db.queryViewByKeys("views/sortedByDate",
                                                     BaseDocument.class,
                                                     list,
                                                     null,
                                                     null);
List<ValueRow> rows = result.getRows();
assertTrue(rows.size() != 0);

// Check that results are actually one of the desired
for (ValueRow row : rows) {
    String date = (String) row.getValue().getProperty("date");
    assertTrue(list.contains(date));
}

In line 2 we define a list of Strings containing those dates that we want to match.

In line 4 we can see the extra argument (the list of keys to match).

Lines 13 through 16 we check that the date on the retrieved documents are actually included in the list.

NOTE: method getRow used in line 14 returns the second argument used in the emit of the map function (the document for this sortedByDate map function).

How do you see it so far?

Advertisements