added indexing options: background, geo, dropDups, etc.
This commit is contained in:
parent
9dd1a5c2e3
commit
367f9b32cc
|
@ -21,8 +21,9 @@ begin
|
||||||
end
|
end
|
||||||
|
|
||||||
module Mongo
|
module Mongo
|
||||||
ASCENDING = 1
|
ASCENDING = 1
|
||||||
DESCENDING = -1
|
DESCENDING = -1
|
||||||
|
GEO2D = '2d'
|
||||||
|
|
||||||
module Constants
|
module Constants
|
||||||
OP_REPLY = 1
|
OP_REPLY = 1
|
||||||
|
|
|
@ -318,14 +318,43 @@ module Mongo
|
||||||
#
|
#
|
||||||
# @param [String, Array] field_or_spec
|
# @param [String, Array] field_or_spec
|
||||||
# should be either a single field name or an array of
|
# should be either a single field name or an array of
|
||||||
# [field name, direction] pairs. Directions should be specified as Mongo::ASCENDING or Mongo::DESCENDING.
|
# [field name, direction] pairs. Directions should be specified
|
||||||
|
# as Mongo::ASCENDING, Mongo::DESCENDING, or Mongo::GEO2D.
|
||||||
#
|
#
|
||||||
# @param [Boolean] unique if true, this index will enforce a uniqueness constraint.
|
# Note that geospatial indexing only work in versions of MongoDB >= 1.3.3+. Keep in mind, too,
|
||||||
|
# that in order to index a given field, that field must reference either an array or a sub-object
|
||||||
|
# where the first two values represent x- and y-coordinates. Examples can be seen below.
|
||||||
|
#
|
||||||
|
# @param [Boolean] unique if true, this index will enforce a uniqueness constraint. DEPRECATED. Future
|
||||||
|
# versions of this driver will specify the uniqueness constraint using a hash param.
|
||||||
|
#
|
||||||
|
# @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,
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# @example Creating a compound index:
|
||||||
|
# @posts.create_index([['subject', Mongo::ASCENDING], ['created_at', Mongo::DESCENDING]])
|
||||||
|
#
|
||||||
|
# @example Creating a geospatial index:
|
||||||
|
# @restaurants.create_index(['location', Mongo::GEO2D])
|
||||||
|
#
|
||||||
|
# # Note that this will work only if 'location' represents x,y coordinates:
|
||||||
|
# {'location': [0, 50]}
|
||||||
|
# {'location': {'x' => 0, 'y' => 50}}
|
||||||
|
# {'location': {'latitude' => 0, 'longitude' => 50}}
|
||||||
|
#
|
||||||
|
# @example A geospatial index with alternate longitude and latitude:
|
||||||
|
# @restaurants.create_index(['location', Mongo::GEO2D], :min => 500, :max => 500)
|
||||||
#
|
#
|
||||||
# @return [String] the name of the index created.
|
# @return [String] the name of the index created.
|
||||||
#
|
#
|
||||||
# @core indexes create_index-instance_method
|
# @core indexes create_index-instance_method
|
||||||
def create_index(field_or_spec, unique=false)
|
def create_index(field_or_spec, opts={})
|
||||||
|
opts.assert_valid_keys(:min, :max, :background, :unique, :dropDups) if opts.is_a?(Hash)
|
||||||
field_h = OrderedHash.new
|
field_h = OrderedHash.new
|
||||||
if field_or_spec.is_a?(String) || field_or_spec.is_a?(Symbol)
|
if field_or_spec.is_a?(String) || field_or_spec.is_a?(Symbol)
|
||||||
field_h[field_or_spec.to_s] = 1
|
field_h[field_or_spec.to_s] = 1
|
||||||
|
@ -333,15 +362,20 @@ module Mongo
|
||||||
field_or_spec.each { |f| field_h[f[0].to_s] = f[1] }
|
field_or_spec.each { |f| field_h[f[0].to_s] = f[1] }
|
||||||
end
|
end
|
||||||
name = generate_index_names(field_h)
|
name = generate_index_names(field_h)
|
||||||
|
if opts == true || opts == false
|
||||||
|
warn "If you're using Collection#create_index, the method for specifying a unique index has changed." +
|
||||||
|
"Please pass :unique => true to the method instead."
|
||||||
|
end
|
||||||
sel = {
|
sel = {
|
||||||
:name => name,
|
:name => name,
|
||||||
:ns => "#{@db.name}.#{@name}",
|
:ns => "#{@db.name}.#{@name}",
|
||||||
:key => field_h,
|
:key => field_h,
|
||||||
:unique => unique }
|
:unique => (opts == true ? true : false) }
|
||||||
|
sel.merge!(opts) if opts.is_a?(Hash)
|
||||||
begin
|
begin
|
||||||
insert_documents([sel], Mongo::DB::SYSTEM_INDEX_COLLECTION, false, true)
|
response = insert_documents([sel], Mongo::DB::SYSTEM_INDEX_COLLECTION, false, true)
|
||||||
rescue Mongo::OperationFailure
|
rescue Mongo::OperationFailure
|
||||||
raise Mongo::OperationFailure, "Failed to create index #{sel.inspect}."
|
raise Mongo::OperationFailure, "Failed to create index #{sel.inspect}. Errors: #{response}"
|
||||||
end
|
end
|
||||||
name
|
name
|
||||||
end
|
end
|
||||||
|
|
|
@ -378,11 +378,11 @@ module Mongo
|
||||||
# @return [Hash] keys are index names and the values are lists of [key, direction] pairs
|
# @return [Hash] keys are index names and the values are lists of [key, direction] pairs
|
||||||
# defining the index.
|
# defining the index.
|
||||||
def index_information(collection_name)
|
def index_information(collection_name)
|
||||||
sel = {:ns => full_collection_name(collection_name)}
|
sel = {:ns => full_collection_name(collection_name)}
|
||||||
info = {}
|
info = {}
|
||||||
Cursor.new(Collection.new(self, SYSTEM_INDEX_COLLECTION), :selector => sel).each { |index|
|
Cursor.new(Collection.new(self, SYSTEM_INDEX_COLLECTION), :selector => sel).each do |index|
|
||||||
info[index['name']] = index['key'].map {|k| k}
|
info[index['name']] = index
|
||||||
}
|
end
|
||||||
info
|
info
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -24,3 +24,14 @@ class Object
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
#:nodoc:
|
||||||
|
class Hash
|
||||||
|
|
||||||
|
#:nodoc:
|
||||||
|
def assert_valid_keys(*valid_keys)
|
||||||
|
unknown_keys = keys - [valid_keys].flatten
|
||||||
|
raise(Mongo::MongoArgumentError, "Unknown key(s): #{unknown_keys.join(", ")}") unless unknown_keys.empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
|
@ -492,7 +492,30 @@ class TestCollection < Test::Unit::TestCase
|
||||||
|
|
||||||
context "Creating indexes " do
|
context "Creating indexes " do
|
||||||
setup do
|
setup do
|
||||||
|
@@db.drop_collection('geo')
|
||||||
|
@@db.drop_collection('test-collection')
|
||||||
@collection = @@db.collection('test-collection')
|
@collection = @@db.collection('test-collection')
|
||||||
|
@geo = @@db.collection('geo')
|
||||||
|
end
|
||||||
|
|
||||||
|
should "create a geospatial index" do
|
||||||
|
@geo.save({'loc' => [-100, 100]})
|
||||||
|
@geo.create_index([['loc', Mongo::GEO2D]])
|
||||||
|
assert @geo.index_information['loc_2d']
|
||||||
|
end
|
||||||
|
|
||||||
|
should "create a unique index" do
|
||||||
|
@collection.create_index([['a', Mongo::ASCENDING]], true)
|
||||||
|
assert @collection.index_information['a_1']['unique'] == true
|
||||||
|
end
|
||||||
|
|
||||||
|
should "create an index in the background" do
|
||||||
|
if @@version > '1.3.1'
|
||||||
|
@collection.create_index([['b', Mongo::ASCENDING]], :background => true)
|
||||||
|
assert @collection.index_information['b_1']['background'] == true
|
||||||
|
else
|
||||||
|
assert true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
should "generate indexes in the proper order" do
|
should "generate indexes in the proper order" do
|
||||||
|
@ -508,7 +531,7 @@ class TestCollection < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
should "return properly ordered index information" do
|
should "return properly ordered index information" do
|
||||||
assert_equal [['b', 1], ['a', 1]], @collection.index_information["b_1_a_1"]
|
assert @collection.index_information['b_1_a_1']
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -133,12 +133,6 @@ class DBAPITest < Test::Unit::TestCase
|
||||||
assert_equal 2, docs.size
|
assert_equal 2, docs.size
|
||||||
assert docs.detect { |row| row['a'] == 1 }
|
assert docs.detect { |row| row['a'] == 1 }
|
||||||
assert docs.detect { |row| row['a'] == 2 }
|
assert docs.detect { |row| row['a'] == 2 }
|
||||||
|
|
||||||
# Find by advanced query (regexp)
|
|
||||||
docs = @@coll.find('a' => /[1|2]/).to_a
|
|
||||||
assert_equal 2, docs.size
|
|
||||||
assert docs.detect { |row| row['a'] == 1 }
|
|
||||||
assert docs.detect { |row| row['a'] == 2 }
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_find_sorting
|
def test_find_sorting
|
||||||
|
@ -287,7 +281,7 @@ class DBAPITest < Test::Unit::TestCase
|
||||||
assert_equal 2, info.length
|
assert_equal 2, info.length
|
||||||
|
|
||||||
assert info.has_key?(name)
|
assert info.has_key?(name)
|
||||||
assert_equal info[name], [["a", ASCENDING]]
|
assert_equal info[name]["key"], {"a" => 1}
|
||||||
ensure
|
ensure
|
||||||
@@db.drop_index(@@coll.name, name)
|
@@db.drop_index(@@coll.name, name)
|
||||||
end
|
end
|
||||||
|
@ -302,7 +296,7 @@ class DBAPITest < Test::Unit::TestCase
|
||||||
assert_equal 2, info.length
|
assert_equal 2, info.length
|
||||||
|
|
||||||
assert info.has_key?(name)
|
assert info.has_key?(name)
|
||||||
assert_equal info[name], [["a", ASCENDING]]
|
assert_equal info[name]['key'], {"a" => 1}
|
||||||
ensure
|
ensure
|
||||||
@@db.drop_index(@@coll.name, name)
|
@@db.drop_index(@@coll.name, name)
|
||||||
end
|
end
|
||||||
|
@ -314,7 +308,7 @@ class DBAPITest < Test::Unit::TestCase
|
||||||
|
|
||||||
assert_equal name, 'a_-1_b_1_c_-1'
|
assert_equal name, 'a_-1_b_1_c_-1'
|
||||||
assert info.has_key?(name)
|
assert info.has_key?(name)
|
||||||
assert_equal [['a', DESCENDING], ['b', ASCENDING], ['c', DESCENDING]], info[name]
|
assert_equal info[name]['key'], {"a" => -1, "b" => 1, "c" => -1}
|
||||||
ensure
|
ensure
|
||||||
@@db.drop_index(@@coll.name, name)
|
@@db.drop_index(@@coll.name, name)
|
||||||
end
|
end
|
||||||
|
@ -326,7 +320,7 @@ class DBAPITest < Test::Unit::TestCase
|
||||||
|
|
||||||
assert_equal name, 'a_-1_b_1_c_-1'
|
assert_equal name, 'a_-1_b_1_c_-1'
|
||||||
assert info.has_key?(name)
|
assert info.has_key?(name)
|
||||||
assert_equal [['a', DESCENDING], ['b', ASCENDING], ['c', DESCENDING]], info[name]
|
assert_equal info[name]['key'], {"a" => -1, "b" => 1, "c" => -1}
|
||||||
ensure
|
ensure
|
||||||
@@db.drop_index(@@coll.name, name)
|
@@db.drop_index(@@coll.name, name)
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue