The argument to the aggregate method is a pipeline which is an array of hashes where each hash is a stage. Your example query is a hash with values that are hashes; too bad that it reads well, but this obscures the misuse. Unfortunately, Moped somehow allows this misuse even though the mongo shell catches it and returns the server error message "exception: A pipeline stage specification object must contain exactly one field." I hope that you like the following, I think that it is what you want.
test/unit/visit_test.rb
require 'test_helper'
require 'json'
class VisitTest < ActiveSupport::TestCase
def setup
Visit.delete_all
puts
end
test "0. mongoid version" do
puts "Mongoid::VERSION:#{Mongoid::VERSION}\nMoped::VERSION:#{Moped::VERSION}"
end
test "project after group" do
data = JSON.parse(<<-EOD
[
{"_id": "527d60865593622ba17643e6", "siteid": "100", "date": 1383940800, "visits": 1},
{"_id": "527d60865593622ba17643e7", "siteid": "200", "date": 1383940801, "visits": 1},
{"_id": "527d60865593622ba17643e8", "siteid": "200", "date": 1383940802, "visits": 1}
]
EOD
)
Visit.create(data)
assert_equal 3, Visit.count
pipeline = [
{"$match" => {"$and" => [{:date => {"$gte" => 1383940800}}, {:date => {"$lt" => 1384027200}}]}},
{"$group" => {"_id" => "$siteid", "visits" => {"$sum" => "$visits"}}},
{"$project" => {"_id" => 0, "siteid" => "$_id", "visits" => 1}}
]
p Visit.collection.aggregate(pipeline)
end
end
rake test
Run options:
# Running tests:
[1/2] VisitTest#test_0._mongoid_version
Mongoid::VERSION:3.1.5
Moped::VERSION:1.5.1
[2/2] VisitTest#test_project_after_group
[{"visits"=>2, "siteid"=>"200"}, {"visits"=>1, "siteid"=>"100"}]
Finished tests in 0.038172s, 52.3944 tests/s, 26.1972 assertions/s.
2 tests, 1 assertions, 0 failures, 0 errors, 0 skips