1

I've run into some strange differences between the mongodb running on MongoHQ and the version running on my own development machine. Specifically, when calling .toString() on an object id inside a MapReduce map function, the results vary:

On my own machine:

ObjectId('foo').toString()  // => 'foo'

On MongoHQ:

ObjectId('foo').toString()  // => 'ObjectId(\'foo\')'

Note: The id's I use are actual mongodb id's - not just 'foo' etc. as in these examples

I would expect .toString() to behave like on my own machine - not how it's behaving on MongoHQ. How come it's not?

My local OSX version of MongoDB is installed using Homebrew and is version 2.0.1-x86_64

To show what's actually going on, I've build a little test case. Let's assume that we have a users collection with a friends attribute, being an array of user ids:

> db.users.find()
{ _id: ObjectId('a'), friends: [ObjectId('b'), ObjectId('c')] },
{ _id: ObjectId('b'), friends: [] },
{ _id: ObjectId('c'), friends: [] }

As you can see a is friends with b and c where as b and c isn't friends with anybody.

Now let's look at a working test-algorithm:

var map = function() {
  this.friends.forEach(function(f) {
    emit(f, { friends: 1, user: user, friend: f.toString() });
  });
};

var reduce = function(k, vals) {
  var result = { friends: 0, user: [], friend: [] };

  vals.forEach(function(val) {
    result.friends += val.friends;
    result.user.push(val.user);
    result.friend.push(val.friend);
  });

  return result;
};

var id = ObjectId('50237c6d5849260996000002');

var query = {
  query   : { friends: id },
  out     : { inline: 1 },
  scope   : { user: id.toString() },
  jsMode  : true,
  verbose : true
};

db.users.mapReduce(map, reduce, query);

Assuming id is set to an id of a user who is a friend of someone in the users collection, then the output returned by the mapReduce method on MongoHQ will look like this:

{
  "results" : [
    {
      "_id" : ObjectId("50237c555849260996000001"),
      "value" : {
        "friends" : 1,
        "user" : "50237c6d5849260996000002",
        "friend" : "ObjectId(\"50237c555849260996000001\")"
      }
    },
    {
      "_id" : ObjectId("50237c74c271be07f6000002"),
      "value" : {
        "friends" : 1,
        "user" : "50237c6d5849260996000002",
        "friend" : "ObjectId(\"50237c74c271be07f6000002\")"
      }
    }
  ],
  "timeMillis" : 0,
  "timing" : {
    "mapTime" : 0,
    "emitLoop" : 0,
    "reduceTime" : 0,
    "mode" : "mixed",
    "total" : 0
  },
  "counts" : {
    "input" : 1,
    "emit" : 2,
    "reduce" : 0,
    "output" : 2
  },
  "ok" : 1,
}

As you can see, the friend attribute in each result is not just a string containing the id, but a string containing the actual method call.

Did I run this on my own machine, the results array would have been:

{
  "_id" : ObjectId("50237c555849260996000001"),
  "value" : {
    "friends" : 1,
    "user" : "50237c6d5849260996000002",
    "friend" : "50237c555849260996000001"
  }
},
{
  "_id" : ObjectId("50237c74c271be07f6000002"),
  "value" : {
    "friends" : 1,
    "user" : "50237c6d5849260996000002",
    "friend" : "50237c74c271be07f6000002"
  }
}
Thomas Watson
  • 6,507
  • 5
  • 33
  • 43

1 Answers1

1

MongoHQ is running a different version of MongoDB than you are.

To get the behavior of your homebrew version, try changing your map function:

var map = function() {
  this.friends.forEach(function(f) {
    emit(f, { friends: 1, user: user.str, friend: f.str });
  });
};
Tad Marshall
  • 1,353
  • 8
  • 10