0

I have a mongodb collection like this

{"assigneeId" => 1000, "status" => 3, "starttime" => "2014 Feb 25", "numofdays => 6} {"assigneeId" => 1000, "status" => 2, "starttime" => "2014 Jan 10", "numofdays => 6} {"assigneeId" => 1000, "status" => 3, "starttime" => "2014 Jan 1", "numofdays => 20}

I wrote a MongoDB query to group the above collection with assigneeId whose status is 3 and add the value of numofdays like this

db.events.group ( { key: {assigneeId:1}, cond: {status: {$gte: 3}}, reduce: function (curr, result) {result.total++; result.numofdays += curr.numofdays;}, initial: {total:0, numofdays:0} })

This gives the output as expected from the Mongodb cli.

When I write the ruby code for executing the same query, I could not make it work. Am getting lot of different hits for similar problem but none of the format seems to work. I could not go past the syntax error in ruby for grouping function. Please note I am not using mongoid. If I could get this work with Aggregation framework, that is also fine with me.

This is the ruby query I wrote and the error for the same.

@events_h.group (
                :cond => {:status => { '$in' => ['3']}},
                :key => 'assigneeId',
                :initial => {count:0},
                :reduce => "function(x, y) {y.count += x.count;}"
                )

Error I am getting

analyze.rb:43: syntax error, unexpected ',', expecting ')' out = @events_h.group (["assigneeId"], { }, { }, "function() { }") ^ analyze.rb:43: syntax error, unexpected ')', expecting keyword_end analyze.rb:83: syntax error, unexpected end-of-input, expecting keyword_end

Any help is much appreciated.

Thanks

Sivaram Kannan
  • 121
  • 1
  • 12
  • Instead of `(` there should be `{` in `(y.count += x.count;}` – Yevgeniy Anfilofyev Mar 26 '14 at 06:38
  • changed and here is the error. First error is still not solved analyze.rb:44: syntax error, unexpected =>, expecting ')' :cond => {:status => { '$in' => ['3']}}, ^ analyze.rb:44: syntax error, unexpected '}', expecting keyword_end :cond => {:status => { '$in' => ['3']}}, ^ – Sivaram Kannan Mar 26 '14 at 07:00

1 Answers1

0

The following test includes solutions for using both methods, group and aggregate. I recommend that you use aggregate, it is faster and avoids JavaScript and consuming a V8 engine. Hope that this helps.

test.rb

require 'mongo'
require 'test/unit'

class MyTest < Test::Unit::TestCase
  def setup
    @events_h = Mongo::MongoClient.new['test']['events_h']
    @docs = [
        {"assigneeId" => 1000, "status" => 3, "starttime" => "2014 Feb 25", "numofdays" => 6},
        {"assigneeId" => 1000, "status" => 2, "starttime" => "2014 Jan 10", "numofdays" => 6},
        {"assigneeId" => 1000, "status" => 3, "starttime" => "2014 Jan 1", "numofdays" => 20}]
    @events_h.remove
    @events_h.insert(@docs)
  end

  test "group" do
    result = @events_h.group(
        :cond => {:status => {'$in' => [3]}},
        :key => 'assigneeId',
        :initial => {numofdays: 0},
        :reduce => "function(x, y) {y.numofdays += x.numofdays;}"
    )
    assert_equal(26, result.first['numofdays'])
    puts "group: #{result.inspect}"
  end

  test "aggregate" do
    result = @events_h.aggregate([
        {'$match' => {:status => {'$in' => [3]}}},
        {'$group' => {'_id' => '$status', 'numofdays' => {'$sum' => '$numofdays'}}}
    ])
    assert_equal(26, result.first['numofdays'])
    puts "aggregate: #{result.inspect}"
  end
end

$ ruby test.rb

Loaded suite test
Started
aggregate: [{"_id"=>3, "numofdays"=>26}]
.group: [{"assigneeId"=>1000.0, "numofdays"=>26.0}]
.

Finished in 0.010575 seconds.

2 tests, 2 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications
100% passed

189.13 tests/s, 189.13 assertions/s
Gary Murakami
  • 3,392
  • 1
  • 16
  • 20