3

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 }
1
  • Are you wanting a sum for each of the individual fields? You probably just need to create separate indexes for each field. Yeah, it's more than 1 query, but that's probably the best way to go about this. Commented Apr 10, 2012 at 3:26

2 Answers 2

6

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.

Sign up to request clarification or add additional context in comments.

Comments

4

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.

1 Comment

Thank you for this answer! I spent hours trying to figure this out.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.