tags:

views:

460

answers:

1

I'm trying to bring back a list of year/month combinations with counts for describing blog posts. The idea is that they will be displayed like so:

  • January 2010 (1 post)
  • December 2009 (2 posts)
  • ...

I have managed to get this to work using the MongoDB JS shell, and it returns results in a useful format:

db.posts.group({ 
    keyf: function(x){ 
                      return { 
                              month: x.datetime.getMonth(), 
                              year:x.datetime.getFullYear() 
                      }; 
    }, 
    reduce: function(x,y){ y.count++ }, 
    initial:{count:0} 
})

Results:

[ { "month" : 0, "year" : 2010, "count" : 3 },
  { "month" : 0, "year" : 1970, "count" : 1 } ]

This is great, exactly what I'm after. However, trying to convert this into code appropriate for the ruby driver, I can't get it to work. I have looked at the documentation and from my understanding, the following should yield the same results (I'm using MongoMapper, hence the Post.collection):

@archive = Post.collection.group(
  "function(x) { return { month: x.datetime.getMonth(), year:x.datetime.getFullYear() }; }",
  nil, { :count => 0 }, 'function(x,y){y.count++}', true)

Instead of giving back the nice array of useful data, I'm getting this mess:

{
  "function(x) { return { month: x.datetime.getMonth(), year:x.datetime.getFullYear() }; }" => nil, 
  "count" => 4.0
}

It seems that either it is completely defying its own documentation (and my understanding of the source code!) or I am missing something fundamental here. I'm almost pulling my hair out, any help gratefully accepted.

A: 

That's pretty strange behavior. I just ran your code locally, and everything worked. Can you verify that you're using the driver version 0.18.2? If so, make sure that that's the only version installed (just as a sanity check).

I don't think it should make any difference, but I wasn't running #group from MongoMapper -- I was using the gem alone. You might try that, too. Here's the code I ran:

require 'rubygems'
require 'mongo'

d = Mongo::Connection.new.db('blog')
c = d['post']

p c.group("function(x) { return { month: x.date.getMonth(), year:x.date.getFullYear() }; }", 
  nil, 
  { :count => 0 }, 
  "function(x,y){y.count++}", 
  true)
Kyle Banker
I have checked the versions and I had 0.18 and 0.18.2 installed. I have removed the old version and updated MongoMapper (the version I had depended on 0.18). The problem still persists. I have also tried using just the driver as you did and in my case it still fails. I don't understand why it'd act different for you than it does me?EDIT: trying this in its own script as you have yields the correct result. It only seems to be failing from within my rails app.
Splash
Hmm. Not sure what effect Rails could possibly have on this. I think the best thing would be for you to create a full failing test case for both me and John (of MongoMapper).
Kyle Banker
Ohh, I have been a monumental pillock. Turns out it was the version difference 0.18 to 0.18.2. I just forgot to restart the dev server after I removed the old gem and updated everything. Going back and looking at the 0.18 source on github, I see that between then and 0.18.2, support for the keyf code was added and that did fix it. I feel suitably silly :)
Splash