diff --git a/lib/mongo/util/bson.rb b/lib/mongo/util/bson.rb index eacc4b0..545fa1b 100644 --- a/lib/mongo/util/bson.rb +++ b/lib/mongo/util/bson.rb @@ -333,7 +333,20 @@ class BSON def serialize_object_element(buf, key, val, opcode=OBJECT) buf.put(opcode) self.class.serialize_cstr(buf, key) - buf.put_array(BSON.new.serialize(val).to_a) + buf.put_array(BSON.new.serialize(put_id_first(val)).to_a) + end + + # For internal use only. Looks for '_id' or :_id key of val. If there is + # one, returns an OrderedHash where '_id' is first. If not, returns val. + def put_id_first(val) + oid = val.delete('_id') || val.delete(:_id) + if oid + h = OrderedHash.new + h['_id'] = oid + val.each { |k, v| h[k] = v } + val = h + end + val end def serialize_array_element(buf, key, val) diff --git a/tests/test_bson.rb b/tests/test_bson.rb index e0604e7..349007e 100644 --- a/tests/test_bson.rb +++ b/tests/test_bson.rb @@ -132,4 +132,20 @@ class BSONTest < Test::Unit::TestCase assert_kind_of Undefined, doc2['undef'] end + def test_put_id_first + val = {'a' => 'foo'} + assert_same val, @b.put_id_first(val) + + val = OrderedHash.new + val['not_id'] = 1 + val['_id'] = 2 + id_first = @b.put_id_first(val) + assert_equal ['_id', 'not_id'], id_first.keys + + val = {'a' => 'foo', 'b' => 'bar', :_id => 42, 'z' => 'hello'} + id_first = @b.put_id_first(val) + assert id_first.keys.include?('_id') + assert !id_first.keys.include?(:_id) + end + end