diff --git a/lib/mongo/collection.rb b/lib/mongo/collection.rb index 78d426a..7d04b7f 100644 --- a/lib/mongo/collection.rb +++ b/lib/mongo/collection.rb @@ -235,30 +235,37 @@ module Mongo # Update a single document in this collection. # - # :spec :: a hash specifying elements which must be present for - # a document to be updated + # :selector :: a hash specifying elements which must be present for a document to be updated. Note: + # the update command currently updates only the first document matching the + # given selector. If you want all matching documents to be updated, be sure + # to specify :multi => true. # :document :: a hash specifying the fields to be changed in the - # selected document, or (in the case of an upsert) the document to - # be inserted + # selected document, or (in the case of an upsert) the document to + # be inserted # # Options: # :upsert :: if true, perform an upsert operation + # :multi :: update all documents matching the selector, as opposed to + # just the first matching document. Note: only works in 1.1.3 or later. # :safe :: if true, check that the update succeeded. OperationFailure - # will be raised on an error. Checking for safety requires an extra - # round-trip to the database - def update(spec, document, options={}) + # will be raised on an error. Checking for safety requires an extra + # round-trip to the database + def update(selector, document, options={}) message = ByteBuffer.new message.put_int(0) BSON.serialize_cstr(message, "#{@db.name}.#{@name}") - message.put_int(options[:upsert] ? 1 : 0) # 1 if a repsert operation (upsert) - message.put_array(BSON.new.serialize(spec, false).to_a) + update_options = 0 + update_options += 1 if options[:upsert] + update_options += 2 if options[:multi] + message.put_int(update_options) + message.put_array(BSON.new.serialize(selector, false).to_a) message.put_array(BSON.new.serialize(document, false).to_a) if options[:safe] @db.send_message_with_safe_check(Mongo::Constants::OP_UPDATE, message, - "db.#{@name}.update(#{spec.inspect}, #{document.inspect})") + "db.#{@name}.update(#{selector.inspect}, #{document.inspect})") else @db.send_message_with_operation(Mongo::Constants::OP_UPDATE, message, - "db.#{@name}.update(#{spec.inspect}, #{document.inspect})") + "db.#{@name}.update(#{selector.inspect}, #{document.inspect})") end end diff --git a/lib/mongo/db.rb b/lib/mongo/db.rb index 0540984..23cc0c7 100644 --- a/lib/mongo/db.rb +++ b/lib/mongo/db.rb @@ -465,7 +465,7 @@ module Mongo end end - # Note: this method is a stub. Will be completed in an upcoming refactoring. + # Send a message to the database and wait for the response. def receive_message_with_operation(operation, message, log_message=nil) message_with_headers = add_message_headers(operation, message).to_s @logger.debug(" MONGODB #{log_message || message}") if @logger diff --git a/test/test_collection.rb b/test/test_collection.rb index a83325c..5f3aa4b 100644 --- a/test/test_collection.rb +++ b/test/test_collection.rb @@ -97,6 +97,20 @@ class TestCollection < Test::Unit::TestCase assert_equal 1, @@test.find_one(:_id => id2)["x"] end + if @@version >= "1.1.3" + def test_multi_update + @@test.save("num" => 10) + @@test.save("num" => 10) + @@test.save("num" => 10) + assert_equal 3, @@test.count + + @@test.update({"num" => 10}, {"$set" => {"num" => 100}}, :multi => true) + @@test.find.each do |doc| + assert_equal 100, doc["num"] + end + end + end + def test_upsert @@test.update({"page" => "/"}, {"$inc" => {"count" => 1}}, :upsert => true) @@test.update({"page" => "/"}, {"$inc" => {"count" => 1}}, :upsert => true) diff --git a/test/unit/collection_test.rb b/test/unit/collection_test.rb index da7506d..2d8c0e8 100644 --- a/test/unit/collection_test.rb +++ b/test/unit/collection_test.rb @@ -38,7 +38,6 @@ class CollectionTest < Test::Unit::TestCase op == 2001 && log.include?("db.books.update") end @coll.update({}, {:title => 'Moby Dick'}, :safe => true) - end should "send safe insert message" do