MarioDS
MarioDS

Reputation: 13063

MongoDB Mapreduce: query/restriction/filter on result of mapreduce?

In querying a mongoDB database with map_reduce, I need to limit the actual results. I was hoping to use the query option but this only restricts data in the map part. I need to restrict output.

My data looks like this (left other attributes out):

 obj1: { name: "obj1", version: 1, someAttr = "a" }, 
 obj1a: { name: "obj1", version: 2, someAttr= "b"},

 obj2: { name: "obj2", version: 1 }, 
 obj2a: { name: "obj2", version: 2} ...

I have objects who share the same name per version (which is incremented per update).

I need to get the newest version of each object, and I have written map/reduce functions (it's done in mongomapper):

MAP:

function() {
  emit(this.name, this);
}

REDUCE:

function(key, values) {
  var res = values[0];
  for(var i=1; i<values.length; i++)
  {
    if(values[i].version >res.version)
    {
      res = values[i];
    }
  }
  return res;
}

Now from time to time I need to restrict results and I juse the query option for that. IT works fine, except in one use case:

I need the latest version of obj1 that has also someAttr set to "a".

So what I tried in query is:

name: "obj1", someAttr: "a"

The expected outcome is an empty result because the latest version does not have someAttr set to "a". What I got is obj1 with version 1...

How can I restrict the output to only those objects with someAttr set to "a"?

Upvotes: 0

Views: 2343

Answers (1)

Makis Tsantekidis
Makis Tsantekidis

Reputation: 2728

You can add to your reduce function

function(key, values) {
  var res = values[0];
  for(var i=1; i<values.length; i++)
  {
    if(values[i].version >res.version)
    {
      res = values[i];
    }
  }
  if ('someAttr' in res && res.someAttr == "a")
  return res;
}

Or if you want to check for the latest version between just the ones that have someAttr set to 'a' you can do

function(key, values) {
  var res = {version : 0}
  for(var i=0; i<values.length; i++)
  {
    if('someAttr' in res && res.someAttr == "a" && values[i].version >res.version)
    {
      res = values[i];
    }
  }
  return res;
}

Upvotes: 2

Related Questions