Ivan
Ivan

Reputation: 103879

Custom Couchbase reduce to count some values only

Having the following map:

function (doc, meta) {
  emit(dateToArray(doc.timestamp), doc.user_id);
}

What changes to I need on this reduce to get a count of user_ids that occur more than once?

function(key, values, rereduce) {
  var counts = {}, id;
  for (var i = 0; i < values.length; i++) {
    id = values[i].replace('-', '_');
    counts[id] = counts[id] || 0;
    counts[id] = counts[id] + 1;
  }
  var total = 0;
  for (id in counts) {
    if (counts[id] > 1) total++;
  }
  return total;
}

I tried it on plain JS passing some array of values, and it works as I expected. Debugging is difficult on Couchbase though (or I don't know how), and I'm not seeing any errors on the error.1 and mapreduce_errors.1 files.

Update: I've been doing some crude debugging, going line by line, and this is what I have so far:

function(key, values, rereduce) {
  var counts = {}, total = 0;
  for (var i = 0; i < values.length; i++) {
    var id = values[i];
    if (id.indexOf('id_') != 0) id = 'id_' + values[i].replace(/-/g, '_');
    return id;
    counts[id] = counts[id] || 0;
    counts[id] = counts[id] + 1;
  }
  for (id in counts) {
    if (counts[id] > 1) total++;
  }
  return total;
}

Notice the return id; line. It returns a modified uuid, prefixed by "id_", just like you'd expect by looking at the code.

But then, if I change that line to return counts; or return total;, the result from Couchbase is "The results of this view is empty." What gives?

Upvotes: 1

Views: 289

Answers (1)

Ivan
Ivan

Reputation: 103879

It was one painful debugging session, but here's the final solution:

function(key, values, rereduce) {
  var counts = {}, total = 0, id;
  if (rereduce) {
    for (var set in values) {
      for (var i in values[set]) {
        counts[i] = (counts[i] || 0) + values[set][i];
      }
    }
    for (f in counts) {
      if (counts[f] > 1) total++;
    }
    return total;
  } else {
    for (var i in values) {
      id = 'id_' + values[i].replace(/-/g, '_');
      counts[id] = (counts[id] || 0) + 1;
    }
    return counts;
  }
}

An extra lesson learned: Couchbase won't return big objects off of a reduce operation. Gotta learn more about that.

Upvotes: 1

Related Questions