Milimber
Milimber

Reputation: 31

CouchDB reduce function with an array of values

I have a map function that returns a value as an array:

emit(doc.created_date, { calories : doc.calories, miles : doc.miles, minutes : doc.minutes, reps : doc.reps, steps : doc.steps, water : doc.water })

I want to run a sum on the calories, miles, minutes and steps for all the returned values. Like

return {"calories":t_cal,"miles":t_mil, "minutes":t_min,"steps":t_step};

I have tried several of the examples the couch wiki and other sites, but i cannot figure out how to access the value array.

I get reduce_overflow_error when i try just summing the values or a null when running a for loop:

for(var i in values) { t_mil = t_mil + values[i].miles }

Upvotes: 3

Views: 5587

Answers (2)

ermouth
ermouth

Reputation: 844

You can do it in an elegant and fast way without JS reduce. Make your map function emit an array, like emit(doc.created_date, [doc.calories, doc.miles, doc.minutes, doc.reps, doc.steps, doc.water]), and then use built-in _sum for reduce.

Result will be an array of sums by columns. Not well known, however very useful feature of CouchDB.

Upvotes: 4

JasonSmith
JasonSmith

Reputation: 73702

I do what you are doing a lot, so it is possible.

Either your object is a little bit over CouchDB's limit, or there is a bug in your code.

You can set the CouchDB config, query_server_config/reduce_limit = "false" and see how it looks.

However, if you are only accumulating four items, I do not think it is a reduce limit issue. What always happens to me is JavaScript problems. For example, adding a number to a string produces a (longer) string. Adding more numbers makes the string longer and longer.

var old_value = "3" // This is a bad value, perhaps from a map function bug
var new_value = 5

new_value = new_value + old_value // I wanted 8, but I got "53"
new_value = new_value + 2012 // I wanted 2020 but I got "532012"

Similar problems occur for arrays and other types.

You have a good start with the map function emitting the same thing that reduce returns (an object). Perhaps you could post some code that you are using. I usually do something like this:

function(keys, vals, rereduce) {
  // reduce function
  var result = {'calories':0, 'miles':0, 'minutes':0, 'steps':0}

  for(var i = 0; i < vals.length; i++) {
    result.calories += vals[i].calories || 0
    result.miles    += vals[i].miles    || 0
    result.minutes  += vals[i].minutes  || 0
    result.steps    += vals[i].steps    || 0
  }

  return result
}

Notice that the reduce output is exactly the same as the map output, so this code works for reducing and re-reducing.

Upvotes: 6

Related Questions