How to Use Mongodb Ruby Driver to Do a "Group" (Group By)

How to use MongoDB Ruby Driver to do a Group (group by)?

I finally got it to work by

Analytic.collection.group(  ['myapp_id'], {:page => 'products'}, 
{:pageviews => 0, :timeOnPage => 0},
"function(x, y) { y.pageviews += x.pageviews; y.timeOnPage += x.timeOnPage }" )

but then I used Map/Reduce afterwards as Map/Reduce seems like a more generic and powerful method.

MongoDB Group using Ruby driver

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)

Mongo Group Query using the Ruby driver

This is how the function finally took shape using the 1.10.0 Mongo gem:

@db.collection("audit_log").group(
[:user, :events],
{'events' => { '$elemMatch' => { 'action' => 'LOGIN_SUCCESS' }}},
{ 'lastLoginTs' => -1, 'loginsCount' => 0 },
"function(current, result){ result.loginsCount++; result.lastLoginTs = Math.max(result.lastLoginTs, current.timeStamp);}",
"function(result){ result.lastLoginDate = new Date(result.lastLoginTs).toISOString().split('T')[0];}"
)

With the Mongo Driver, you leave off the keys: "key", "cond", "initial", "reduce", "finalize" and simply pass in the respective values.

I've linked to two approaches taken by other SO users here and here.

Grouping by Polygons in MongoDB

When you want to group, you need to use the aggregation framework. You will need an aggregation pipeline with two steps and an optional 3rd step:

  1. The above query with a $match operator (by the way: the $and is unnecessary. You can put "geometry.coordinates" and "properties.time" in the same associative array)
  2. a $group operator which _id => "$cityname" (I guessed cityname is the field where the name of the city is stored) and "number_of_points" => { "$sum" => 1 }. The new field number_of_points will contain the number of points per city.
  3. (optional) The name of the city will now be in the field _id. When you want the field to have a different name, you can rename it with an additional $project step.

Count operation with parameters with mongodb ruby driver

Is it possible use the count() Mongodb feature with filter parameters in some other way?

From the shell (command-line), you can do the following:

db.collection.find({ data : value}).count()

Obviously, you'll have to do something similar with Ruby, but it should be pretty straightforward.

How to do build this mongoDB query (mongomapper)

Thanks to @Simon I had a look at Map Reduce with MongoMapper. My take on it is probably not perfect, but it does what I want it to do. Here's the implementation:

class ChildTemplate
...
key :name, String
key :version, Integer, :default => 1

...

private
def self.map
<<-JS
function() {
emit(this.name, this);
}
JS
end

private
def self.reduce
<<-JS
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;
}
end

def self.latest_versions(opts = {})
results = []
opts[:out] = "ct_latest_versions"
ChildTemplate.collection.map_reduce(map, reduce, opts).find().each do |map_hash|
results << map_hash["value"]
end
return results
end

Difference with count result in Mongo group by query with Ruby/Javascript

JavaScript doesn't distinguish between floats and ints. It has one Number type that is implemented as a double. So what you are seeing in Ruby is correct, the mongo shell output follows javascript printing conventions and displays Numbers that don't have a decimal component without the '.0'

Mongo ruby driver: Running/getting mongostats/query Graphs

Rather than righting your own, you can just set up MMS and use that instead.

But, if you do want to pull the data directly, you can do that too - anything that can be run from the shell can be run from the driver. So, for example, to run the stats() command, which translates on the command line to:

db.runCommand({dbstats : 1})

And so, just follow the guidelines at the top of the ruby driver FAQ - the first one includes how to run any of the commands via the driver.



Related Topics



Leave a reply



Submit