diff --git a/lib/mongo/collection.rb b/lib/mongo/collection.rb index d4c026e..f588096 100644 --- a/lib/mongo/collection.rb +++ b/lib/mongo/collection.rb @@ -302,12 +302,33 @@ module XGen # # Returns an array of grouped items. # - # :keys :: list of fields to group by + # :keys :: Array of fields to group by # :condition :: specification of rows to be considered (as a 'find' # query specification) # :initial :: initial value of the aggregation counter object # :reduce :: aggregation function as a JavaScript string - def group(keys, condition, initial, reduce) + # :command :: if true, run the group as a command instead of in an + # eval - it is likely that this option will eventually be + # deprecated and all groups will be run as commands + def group(keys, condition, initial, reduce, command=false) + if command + hash = {} + keys.each do |k| + hash[k] = 1 + end + result = @db.db_command({"group" => + { + "ns" => @name, + "$reduce" => Code.new(reduce), + "key" => hash, + "cond" => condition, + "initial" => initial}}) + if result["ok"] == 1 + return result["retval"] + else + raise OperationFailure, "group command failed: #{result['errmsg']}" + end + end group_function = < 0}, "function (obj, prev) { prev.count++; }") + assert_equal [], test.group([], {}, {"count" => 0}, "function (obj, prev) { prev.count++; }", true) test.insert("a" => 2) test.insert("b" => 5) test.insert("a" => 1) assert_equal 3, test.group([], {}, {"count" => 0}, "function (obj, prev) { prev.count++; }")[0]["count"] + assert_equal 3, test.group([], {}, {"count" => 0}, "function (obj, prev) { prev.count++; }", true)[0]["count"] assert_equal 1, test.group([], {"a" => {"$gt" => 1}}, {"count" => 0}, "function (obj, prev) { prev.count++; }")[0]["count"] + assert_equal 1, test.group([], {"a" => {"$gt" => 1}}, {"count" => 0}, "function (obj, prev) { prev.count++; }", true)[0]["count"] test.insert("a" => 2, "b" => 3) expected = [{"a" => 2, "count" => 2}, {"a" => nil, "count" => 1}, {"a" => 1, "count" => 1}] assert_equal expected, test.group(["a"], {}, {"count" => 0}, "function (obj, prev) { prev.count++; }") + assert_equal expected, test.group(["a"], {}, {"count" => 0}, "function (obj, prev) { prev.count++; }", true) assert_raise OperationFailure do test.group([], {}, {}, "5 ++ 5") end + assert_raise OperationFailure do + test.group([], {}, {}, "5 ++ 5", true) + end end def test_deref