Blank value in the result of Map Reduce view

Hi,
I created a mapreduce view in Couchbase to find the latest location of each person.
The documents are as following (multiple documents for same PersonID do exist) :

{
  "_id": "PersonLocation::C38A2B74-166B-4EDE-A6E1-5B2DDE9350BB",
  "PersonID": "AB62CD5B-ADDA-45E9-AFFE-76F4C0B97B52",
  "CaptureDate": "2017-07-24T19:04:49.657",
  "LocationID": "6E3E0CC4-FD8A-4602-8E68-C07E00DB6610",
  "type": "PersonLocation"
},
{
  "_id": "PersonLocation::930077A9-00DA-47C9-8A2C-8AB47ACFB83E",
  "PersonID": "DD658CE5-BC54-4AB7-8DEC-544AD6662E09",
  "CaptureDate": "2017-07-24T19:04:49.697",
  "LocationID": "BC0E7923-3EDA-4CEF-864F-9B50AA218BBB",
  "type": "PersonLocation"
}.....

The map function is:

function (doc, meta) {
  if(doc.type =="PersonLocation"){
    emit(doc.PersonID,{'LocationID':doc.LocationID, 'CaptureDate':doc.CaptureDate})
  }
}

And reduce function is:

 function (keys, values) {
 var LatestDate =''
 var LatestLocation = ''

    for (var i = 0; i < values.length; i++)
 {
   var obj = values[i];
   if(obj.CaptureDate > LatestDate)
   {
        LatestDate = obj.CaptureDate;
        LatestLocation =obj.LocationID
   }
 }
   return LatestLocation
}

After setting group-> true and reduce -> true, I get a somewhat correct result but some records are not correct as their ‘LatestLocation’ is showing as blank ("") clearly meaning that the variable is not being updated for some reason.
PFA screenshot of the result:

I checked and am pretty sure the LocationID and CaptureDate do exist in every single document. I tried studying about rereduce but couldn’t get the hang of it and I’m afraid this is what’s preventing me from getting the correct result. Please help

Hi @krishan.jangid, since you want to reduce based on two attributes, your reduce function needs to return those two attributes.

Try this for your reduce function

function (keys, values) {
  var response = {"LocationID":"", "CaptureDate":""};
  for (var i = 0; i < values.length; i++)
  {
    var obj = values[i];
    if(obj.CaptureDate > response.CaptureDate)
    {
      response.LocationId = obj.LocationID;
      response.CaptureDate = obj.CaptureDate;
    }
  }
  return response;
}
1 Like

Thanks a lot @jkurtz !! Its working. Just needed a small correction in the code you gave.

  response.LocationID = obj.LocationID; 

(the ‘d’ is in uppercase in LocationID.)
One more question. I am still not clear about the reason you gave saying I have to return both attributes. Could you please explain it a bit more?

Sure, map-reduce is used to achieve high throughput by working on subsets of the data and combing those results. That means that a single thread or process must provide its result in a format that can be merged with the results of any number of other processes. In Couchbase’s case, it may be that it’s using multiple threads to process documents in one data node or it is gathering map-reduce results from other data nodes and merging them.

So the output of the reduce function will be the input to another reduce function. That’s why the output in your case needs both attributes.

This is pretty straightforward for counts and maximums, but when the result is based on the entire data set, like determining an average, then you need to include the rereduce flag and account for prior processing.

Cheers,

Jeff

1 Like