2
votes

I have a sample database in CouchDB with the information of a number of aircraft, and a view which shows the manufacturer as key and the model as the value.

The map function is

function(doc) {
    emit(doc["Manufacturer"], doc._id)
}

and the reduce function is

function(keys, values, rereduce){
    return values.length;
}

This is pretty simple. And I indeed get the correct result when I show the view using Futon, where I have 26 aircraft of Boeing:

"BOEING"    26

But if I use a REST client to query the view using

http://localhost:6060/aircrafts/_design/basic/_view/VendorProducts?key="BOEING"

I get

{"rows":[
    {"key":null,"value":2}
]}

I have tested different clients (including web browser, REST client extensions, and curl), all give me the value 2! While queries with other keys work correctly.

Is there something wrong with the MapReduce function or my query?

2

2 Answers

2
votes

The issue could be because of grouping

Using group=true (which is Futon's default), you get a separate reduce value for each unique key in the map - that is, all values which share the same key are grouped together and reduced to a single value.

Were you passing group=true as a query parameter when querying with curl etc? Since it is passed by default in futon you saw the results like

BOEING : 26

Where as without group=true only the reduced value was being returned.

So try this query

http://localhost:6060/aircrafts/_design/basic/_view/VendorProducts?key="BOEING"&group=true

1
votes

You seem to be falling into the re-reduce-trap. Couchdb strictly speaking uses a map-reduce-rereduce process.

  • Map: reformats your data in the output format.
  • Reduce: aggregates the data of several (but not all entries with the same key) - which works correctly in your case.
  • Re-reduce: does the same as reduce, but on previously reduced data.

As you change the format of the value in the reduce stage, the re-reduce call will aggregate the number of already reduced values.

Solutions:

  1. You can just set the value in the map to 1 and reduce a sum of the values.
  2. You check for rereduce==true and in that case return a sum of the values - which will be the integer values returned by the initial reduce.