add group method on collections

This commit is contained in:
Mike Dirolf 2009-04-27 14:19:38 -04:00
parent 2dffc4b504
commit 29cdfe64f1
2 changed files with 56 additions and 0 deletions

View File

@ -139,6 +139,48 @@ module XGen
@db.drop_collection(@name)
end
# Perform a query similar to an SQL group by operation.
#
# Returns an array of grouped items.
#
# :keys :: list 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)
group_function = <<EOS
function () {
var c = db[ns].find(condition);
var map = new Map();
var reduce_function = #{reduce};
while (c.hasNext()) {
var obj = c.next();
var key = {};
for (var i in keys) {
key[keys[i]] = obj[keys[i]];
}
var aggObj = map[key];
if (aggObj == null) {
var newObj = Object.extend({}, key);
aggObj = map[key] = Object.extend(newObj, initial);
}
reduce_function(obj, aggObj);
}
return {"result": map.values()};
}
EOS
return @db.eval(Code.new(group_function,
{
"ns" => @name,
"keys" => keys,
"condition" => condition,
"initial" => initial
}))["result"]
end
# Return an array of hashes, one for each index. Each hash contains:
#
# :name :: Index name

View File

@ -530,6 +530,20 @@ class DBAPITest < Test::Unit::TestCase
assert id != 0
end
def test_group
@@db.drop_collection("test")
test = @@db.collection("test")
assert_equal [], test.group([], {}, {"count" => 0}, "function (obj, prev) { prev.count++; }")
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 1, test.group([], {"a" => {"$gt" => 1}}, {"count" => 0}, "function (obj, prev) { prev.count++; }")[0]["count"]
end
# TODO this test fails with error message "Undefed Before end of object"
# That is a database error. The undefined type may go away.