diff --git a/bin/standard_benchmark b/bin/standard_benchmark index 2363f86..8e8bb96 100755 --- a/bin/standard_benchmark +++ b/bin/standard_benchmark @@ -80,7 +80,7 @@ benchmark('batch insert (medium, no index)', insert_batch, PER_TRIAL/BATCH_SIZE, benchmark('batch insert (large, no index)', insert_batch, PER_TRIAL/BATCH_SIZE, db, 'large_bulk', LARGE) find_one = Proc.new { |coll, x, i| - coll.find_first('x' => x) + coll.find_one('x' => x) } benchmark('find_one (small, no index)', find_one, PER_TRIAL, db, 'small_none', PER_TRIAL / 2) benchmark('find_one (medium, no index)', find_one, PER_TRIAL, db, 'medium_none', PER_TRIAL / 2) diff --git a/examples/benchmarks.rb b/examples/benchmarks.rb index 3b7d71c..2a78632 100644 --- a/examples/benchmarks.rb +++ b/examples/benchmarks.rb @@ -1,5 +1,5 @@ require "benchmark" - + $LOAD_PATH[0,0] = File.join(File.dirname(__FILE__), '..', 'lib') require 'mongo' @@ -20,21 +20,21 @@ arr = (0..OBJS_COUNT).collect {|x| { :number => x, :rndm => (rand(5)+1), :msg => puts "Running benchmark" Benchmark.bmbm do |results| - results.report("single object inserts: ") { + results.report("single object inserts: ") { TEST_COUNT.times { coll.clear - arr.each {|x| coll.insert(x)} + arr.each {|x| coll.insert(x)} } } - results.report("multiple object insert: ") { + results.report("multiple object insert: ") { TEST_COUNT.times { coll.clear coll.insert(arr) } } - results.report("find_first: ") { + results.report("find_one: ") { TEST_COUNT.times { - coll.find_first(:number => 0) + coll.find_one(:number => 0) } } end diff --git a/lib/mongo/collection.rb b/lib/mongo/collection.rb index aa63698..702963d 100644 --- a/lib/mongo/collection.rb +++ b/lib/mongo/collection.rb @@ -89,8 +89,34 @@ module XGen @db.query(self, Query.new(selector, fields, offset, limit, sort, hint, snapshot)) end + # Get a single object from the database. + # + # Raises TypeError if the argument is of an improper type. Returns a + # single document (hash), or nil if no result is found. + # + # :spec_or_object_id :: a hash specifying elements which must be + # present for a document to be included in the result set OR an + # instance of ObjectID to be used as the value for an _id query. + # if nil an empty spec, {}, will be used. + def find_one(spec_or_object_id=nil) + spec = case spec_or_object_id + when nil + {} + when ObjectID + {:_id => spec_or_object_id} + when Hash + spec_or_object_id + else + raise TypeError, "spec_or_object_id must be an instance of ObjectID or Hash, or nil" + end + find(spec, :limit => -1).next_object + end + + # DEPRECATED - use find_one instead + # # Find the first record that matches +selector+. See #find. def find_first(selector={}, options={}) + warn "Collection#find_first is deprecated and will be removed. Please use Collection#find_one instead." h = options.dup h[:limit] = 1 cursor = find(selector, h) diff --git a/lib/mongo/db.rb b/lib/mongo/db.rb index a0bf087..5b18c4b 100644 --- a/lib/mongo/db.rb +++ b/lib/mongo/db.rb @@ -410,7 +410,7 @@ module XGen # Dereference a DBRef, getting the document it points to. def dereference(dbref) - collection(dbref.namespace).find_first("_id" => dbref.object_id) + collection(dbref.namespace).find_one("_id" => dbref.object_id) end # Evaluate a JavaScript expression on MongoDB. diff --git a/tests/mongo-qa/stress1 b/tests/mongo-qa/stress1 index 345151b..d9d808c 100755 --- a/tests/mongo-qa/stress1 +++ b/tests/mongo-qa/stress1 @@ -22,7 +22,7 @@ n1.times { |i| puts n2.times { |i| - x = c.find_first({:id => i}) + x = c.find_one({:id => i}) x['subarray'] = "foo#{i}" p x c.modify({:id => i}, x) diff --git a/tests/test_collection.rb b/tests/test_collection.rb index bfe9adc..bb952dd 100644 --- a/tests/test_collection.rb +++ b/tests/test_collection.rb @@ -34,7 +34,7 @@ class TestCollection < Test::Unit::TestCase def test_safe_insert a = {"hello" => "world"} @@test.insert(a) - a = @@test.find_first() # TODO we need this because insert doesn't add _id + a = @@test.find_one() # TODO we need this because insert doesn't add _id @@test.insert(a) assert @@db.error.include? "E11000" @@ -47,12 +47,12 @@ class TestCollection < Test::Unit::TestCase id1 = @@test.save("x" => 5) @@test.update({}, {"$inc" => {"x" => 1}}) assert_equal 1, @@test.count() - assert_equal 6, @@test.find_first(:_id => id1)["x"] + assert_equal 6, @@test.find_one(:_id => id1)["x"] id2 = @@test.save("x" => 1) @@test.update({"x" => 6}, {"$inc" => {"x" => 1}}) - assert_equal 7, @@test.find_first(:_id => id1)["x"] - assert_equal 1, @@test.find_first(:_id => id2)["x"] + assert_equal 7, @@test.find_one(:_id => id1)["x"] + assert_equal 1, @@test.find_one(:_id => id2)["x"] end def test_upsert @@ -60,7 +60,7 @@ class TestCollection < Test::Unit::TestCase @@test.update({"page" => "/"}, {"$inc" => {"count" => 1}}, :upsert => true) assert_equal 1, @@test.count() - assert_equal 2, @@test.find_first()["count"] + assert_equal 2, @@test.find_one()["count"] end def test_safe_update @@ -86,5 +86,24 @@ class TestCollection < Test::Unit::TestCase @@test.save({"hello" => "world"}, :safe => true) end end + + def test_find_one + id = @@test.save("hello" => "world") + + assert_equal "world", @@test.find_one()["hello"] + assert_equal @@test.find_one(id), @@test.find_one() + assert_equal @@test.find_one(nil), @@test.find_one() + assert_equal @@test.find_one({}), @@test.find_one() + assert_equal @@test.find_one("hello" => "world"), @@test.find_one() + assert_equal @@test.find_one(OrderedHash["hello", "world"]), @@test.find_one() + + assert_equal nil, @@test.find_one("hello" => "foo") + assert_equal nil, @@test.find_one(OrderedHash["hello", "foo"]) + assert_equal nil, @@test.find_one(ObjectID.new) + + assert_raise TypeError do + @@test.find_one(6) + end + end end diff --git a/tests/test_db.rb b/tests/test_db.rb index db2ed2c..3163ec9 100644 --- a/tests/test_db.rb +++ b/tests/test_db.rb @@ -80,7 +80,7 @@ class DBTest < Test::Unit::TestCase insert_id = coll.insert('name' => 'Fred', 'age' => 42) # new id gets added to returned object - row = coll.find_first({'name' => 'Fred'}, :limit => 1) + row = coll.find_one({'name' => 'Fred'}) oid = row['_id'] assert_not_nil oid assert_equal insert_id, oid @@ -88,7 +88,7 @@ class DBTest < Test::Unit::TestCase oid = XGen::Mongo::Driver::ObjectID.new data = {'_id' => oid, 'name' => 'Barney', 'age' => 41} coll.insert(data) - row = coll.find_first({'name' => data['name']}, :limit => 1) + row = coll.find_one({'name' => data['name']}) db_oid = row['_id'] assert_equal oid, db_oid assert_equal data, row @@ -152,7 +152,7 @@ class DBTest < Test::Unit::TestCase assert_equal 1, prev_error['nPrev'] assert_equal prev_error["err"], @@db.error - @@db.collection('test').find_first + @@db.collection('test').find_one assert_nil @@db.error assert !@@db.error? assert @@db.previous_error diff --git a/tests/test_db_api.rb b/tests/test_db_api.rb index 06a4ebb..628ea4b 100644 --- a/tests/test_db_api.rb +++ b/tests/test_db_api.rb @@ -52,11 +52,11 @@ class DBAPITest < Test::Unit::TestCase oh['b'] = 'foo' oid = @@coll.save(oh) - assert_equal 'foo', @@coll.find_first(:_id => oid)['b'] + assert_equal 'foo', @@coll.find_one(oid)['b'] oh = OrderedHash['a' => 1, 'b' => 'foo'] oid = @@coll.save(oh) - assert_equal 'foo', @@coll.find_first(:_id => oid)['b'] + assert_equal 'foo', @@coll.find_one(oid)['b'] end def test_insert_multiple @@ -246,9 +246,9 @@ class DBAPITest < Test::Unit::TestCase assert_equal 1, x['a'] end - def test_find_first_no_records + def test_find_one_no_records @@coll.clear - x = @@coll.find_first('a' => 1) + x = @@coll.find_one('a' => 1) assert_nil x end @@ -473,28 +473,28 @@ class DBAPITest < Test::Unit::TestCase def test_replace assert_equal @@coll.count, 1 - assert_equal @@coll.find_first["a"], 1 + assert_equal @@coll.find_one["a"], 1 @@coll.replace({"a" => 1}, {"a" => 2}) assert_equal @@coll.count, 1 - assert_equal @@coll.find_first["a"], 2 + assert_equal @@coll.find_one["a"], 2 @@coll.replace({"b" => 1}, {"a" => 3}) assert_equal @@coll.count, 1 - assert_equal @@coll.find_first["a"], 2 + assert_equal @@coll.find_one["a"], 2 end def test_repsert assert_equal @@coll.count, 1 - assert_equal @@coll.find_first["a"], 1 + assert_equal @@coll.find_one["a"], 1 @@coll.repsert({"a" => 1}, {"a" => 2}) assert_equal @@coll.count, 1 - assert_equal @@coll.find_first["a"], 2 + assert_equal @@coll.find_one["a"], 2 @@coll.repsert({"b" => 1}, {"a" => 3}) assert_equal @@coll.count, 2 - assert @@coll.find_first({"a" => 3}) + assert @@coll.find_one({"a" => 3}) end def test_to_a @@ -544,7 +544,7 @@ class DBAPITest < Test::Unit::TestCase assert_equal 3, @@db.eval('function (x) {return x;}', 3) assert_equal nil, @@db.eval("function (x) {db.test_eval.save({y:x});}", 5) - assert_equal 5, @@db.collection('test_eval').find_first['y'] + assert_equal 5, @@db.collection('test_eval').find_one['y'] assert_equal 5, @@db.eval("function (x, y) {return x + y;}", 2, 3) assert_equal 5, @@db.eval("function () {return 5;}") @@ -591,7 +591,7 @@ class DBAPITest < Test::Unit::TestCase val = Hash.new(0) val["x"] = 5 @@coll.insert val - id = @@coll.find_first("x" => 5)["_id"] + id = @@coll.find_one("x" => 5)["_id"] assert id != 0 end @@ -614,7 +614,7 @@ class DBAPITest < Test::Unit::TestCase assert_equal nil, @@db.dereference(DBRef.new("test", ObjectID.new)) @@coll.insert({"x" => "hello"}) - key = @@coll.find_first()["_id"] + key = @@coll.find_one()["_id"] assert_equal "hello", @@db.dereference(DBRef.new("test", key))["x"] assert_equal nil, @@db.dereference(DBRef.new("test", 4)) @@ -636,17 +636,17 @@ class DBAPITest < Test::Unit::TestCase assert_kind_of ObjectID, id assert_equal 1, @@coll.count - assert_equal id, @@coll.save(@@coll.find_first) + assert_equal id, @@coll.save(@@coll.find_one) assert_equal 1, @@coll.count - assert_equal "world", @@coll.find_first()["hello"] + assert_equal "world", @@coll.find_one()["hello"] - doc = @@coll.find_first + doc = @@coll.find_one doc["hello"] = "mike" @@coll.save(doc) assert_equal 1, @@coll.count - assert_equal "mike", @@coll.find_first()["hello"] + assert_equal "mike", @@coll.find_one()["hello"] @@coll.save(a) assert_equal 2, @@coll.count @@ -655,7 +655,7 @@ class DBAPITest < Test::Unit::TestCase def test_save_long @@coll.clear @@coll.insert("x" => 9223372036854775807) - assert_equal 9223372036854775807, @@coll.find_first()["x"] + assert_equal 9223372036854775807, @@coll.find_one()["x"] end def test_find_by_oid @@ -665,13 +665,13 @@ class DBAPITest < Test::Unit::TestCase id = @@coll.save("hello" => "world") assert_kind_of ObjectID, id - assert_equal "world", @@coll.find_first(:_id => id)["hello"] + assert_equal "world", @@coll.find_one(:_id => id)["hello"] @@coll.find(:_id => id).to_a.each do |doc| assert_equal "world", doc["hello"] end id = ObjectID.from_string(id.to_s) - assert_equal "world", @@coll.find_first(:_id => id)["hello"] + assert_equal "world", @@coll.find_one(:_id => id)["hello"] end def test_save_with_object_that_has_id_but_does_not_actually_exist_in_collection @@ -680,12 +680,12 @@ class DBAPITest < Test::Unit::TestCase a = {'_id' => '1', 'hello' => 'world'} @@coll.save(a) assert_equal(1, @@coll.count) - assert_equal("world", @@coll.find_first()["hello"]) + assert_equal("world", @@coll.find_one()["hello"]) a["hello"] = "mike" @@coll.save(a) assert_equal(1, @@coll.count) - assert_equal("mike", @@coll.find_first()["hello"]) + assert_equal("mike", @@coll.find_one()["hello"]) end def test_invalid_key_names