willpnw
willpnw

Reputation: 775

How to get all maxes from couchbase using map/reduce?

I've got a lot of records like:

{
   "id": "1000",
   "lastSeen": "2018-02-26T18:49:21.863Z"
}
{
   "id": "1000",
   "lastSeen": "2017-02-26T18:49:21.863Z"
}
{
   "id": "2000",
   "lastSeen": "2018-02-26T18:49:21.863Z"
}
{
   "id": "2000",
   "lastSeen": "2017-02-26T18:49:21.863Z"
}

I'd like to get the most recent records for all ids. So in this case the output would be the following(most recent record for ids 1000 and 2000):

{
   "id": "1000",
   "lastSeen": "2018-02-26T18:49:21.863Z"
}

{
   "id": "2000",
   "lastSeen": "2018-02-26T18:49:21.863Z"
}

With N1QL, this would be

SELECT id, MAX(lastSeen) FROM mybucket GROUP BY id

How would I do this using a couchbase view and map/reduce?

Thanks!

Upvotes: 1

Views: 33

Answers (2)

Chinh Nguyen
Chinh Nguyen

Reputation: 663

You can query by descending and reduce to first one on list as below: Map:

function (doc, meta) {
  emit(doc.id, doc.lastSeen);
}

Reduce:

function reduce(key, values, rereduce) {
    return values[0];
}

Filter:

?inclusive_end=true&skip=0&full_set=&group_level=1&descending=true

This will eliminate the overhead of sorting the grouped values inside reduce function.

Upvotes: 0

Matthew Groves
Matthew Groves

Reputation: 26151

I am far from a regular user of map/reduce, and there may be more efficient JavaScript, but try this:

Map

function (doc, meta) {
  emit(doc.id, doc.lastSeen);
}

Reduce

function reduce(key, values, rereduce) {
    var max = values.sort().reverse()[0];
    return max;
}

Filter: ?limit=6&stale=false&connection_timeout=60000&inclusive_end=true&skip=0&full_set=true&group_level=1

The idea is to sort all the values being emitted (lastSeen). Since they are ISO 8601 and can be lexigraphically sorted, sort() works just fine. You want the latest, so that's what the reverse() is for (otherwise you'd get the oldest).

The filter has a group_level of 1, so it will group by the doc.id field.

Upvotes: 1

Related Questions