From 5aa8721b25e484573af15d7828ddd0372a106ce0 Mon Sep 17 00:00:00 2001 From: Kyle Banker Date: Tue, 2 Nov 2010 14:50:02 -0400 Subject: [PATCH] Allow idiomatic :drop_dups in addition to :dropDups on index creation. Don't raise exception if :dropDups results in duplicate key error. --- lib/mongo/collection.rb | 23 +++++++++++++++-------- test/collection_test.rb | 16 ++++++++++++++++ 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/lib/mongo/collection.rb b/lib/mongo/collection.rb index a67ae8f..5e4f2d2 100644 --- a/lib/mongo/collection.rb +++ b/lib/mongo/collection.rb @@ -358,10 +358,10 @@ module Mongo # @option opts [Boolean] :unique (false) if true, this index will enforce a uniqueness constraint. # @option opts [Boolean] :background (false) indicate that the index should be built in the background. This # feature is only available in MongoDB >= 1.3.2. - # @option opts [Boolean] :dropDups If creating a unique index on a collection with pre-existing records, + # @option opts [Boolean] :drop_dups (nil) If creating a unique index on a collection with pre-existing records, # this option will keep the first document the database indexes and drop all subsequent with duplicate values. - # @option opts [Integer] :min specify the minimum longitude and latitude for a geo index. - # @option opts [Integer] :max specify the maximum longitude and latitude for a geo index. + # @option opts [Integer] :min (nil) specify the minimum longitude and latitude for a geo index. + # @option opts [Integer] :max (nil) specify the maximum longitude and latitude for a geo index. # # @example Creating a compound index: # @posts.create_index([['subject', Mongo::ASCENDING], ['created_at', Mongo::DESCENDING]]) @@ -381,7 +381,7 @@ module Mongo # # @core indexes create_index-instance_method def create_index(spec, opts={}) - opts.assert_valid_keys(:min, :max, :name, :background, :unique, :dropDups) + opts[:dropDups] = opts.delete(:drop_dups) if opts[:drop_dups] field_spec = BSON::OrderedHash.new if spec.is_a?(String) || spec.is_a?(Symbol) field_spec[spec.to_s] = 1 @@ -407,10 +407,17 @@ module Mongo :key => field_spec } selector.merge!(opts) - begin - response = insert_documents([selector], Mongo::DB::SYSTEM_INDEX_COLLECTION, false, true) - rescue Mongo::OperationFailure - raise Mongo::OperationFailure, "Failed to create index #{selector.inspect} with the following errors: #{response}" + + insert_documents([selector], Mongo::DB::SYSTEM_INDEX_COLLECTION, false, false) + response = @db.get_last_error + + if response['err'] + if response['code'] == 11000 && selector[:dropDups] + # NOP. If the user is intentionally dropping dups, we can ignore duplicate key errors. + else + raise Mongo::OperationFailure, "Failed to create index #{selector.inspect} with the following error: " + + "#{response['err']}" + end end name end diff --git a/test/collection_test.rb b/test/collection_test.rb index 44a58f5..45c5ae7 100644 --- a/test/collection_test.rb +++ b/test/collection_test.rb @@ -628,6 +628,22 @@ class TestCollection < Test::Unit::TestCase assert @collection.index_information['a_1']['unique'] == true end + should "drop duplicates" do + @collection.insert({:a => 1}) + @collection.insert({:a => 1}) + assert_equal 2, @collection.find({:a => 1}).count + @collection.create_index([['a', Mongo::ASCENDING]], :unique => true, :dropDups => true) + assert_equal 1, @collection.find({:a => 1}).count + end + + should "drop duplicates with ruby-like drop_dups key" do + @collection.insert({:a => 1}) + @collection.insert({:a => 1}) + assert_equal 2, @collection.find({:a => 1}).count + @collection.create_index([['a', Mongo::ASCENDING]], :unique => true, :drop_dups => true) + assert_equal 1, @collection.find({:a => 1}).count + end + should "create an index in the background" do if @@version > '1.3.1' @collection.create_index([['b', Mongo::ASCENDING]], :background => true)