Skip to content

Commit

Permalink
Merge pull request #170 from estolfo/index_tests
Browse files Browse the repository at this point in the history
RUBY-564 Support for (hashed, text, 2dsphere) index types
  • Loading branch information
estolfo committed Mar 12, 2013
2 parents 6428bf6 + 26b7ddc commit 6b80321
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 18 deletions.
11 changes: 11 additions & 0 deletions lib/mongo.rb
Expand Up @@ -2,7 +2,18 @@ module Mongo
ASCENDING = 1 ASCENDING = 1
DESCENDING = -1 DESCENDING = -1
GEO2D = '2d' GEO2D = '2d'
GEO2DSPHERE = '2dsphere'
GEOHAYSTACK = 'geoHaystack' GEOHAYSTACK = 'geoHaystack'
TEXT = 'text'
HASHED = 'hashed'
INDEX_TYPES = [ ASCENDING,
DESCENDING,
GEO2D,
GEO2DSPHERE,
GEOHAYSTACK,
TEXT,
HASHED
]


DEFAULT_MAX_BSON_SIZE = 4 * 1024 * 1024 DEFAULT_MAX_BSON_SIZE = 4 * 1024 * 1024
DEFAULT_MAX_MESSAGE_SIZE = DEFAULT_MAX_BSON_SIZE * 2 DEFAULT_MAX_MESSAGE_SIZE = DEFAULT_MAX_BSON_SIZE * 2
Expand Down
39 changes: 23 additions & 16 deletions lib/mongo/collection.rb
Expand Up @@ -483,8 +483,9 @@ def update(selector, document, opts={})
# #
# @param [String, Array] spec # @param [String, Array] 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 # [field name, type] pairs. Index types should be specified
# as Mongo::ASCENDING, Mongo::DESCENDING, or Mongo::GEO2D. # as Mongo::ASCENDING, Mongo::DESCENDING, Mongo::GEO2D, Mongo::GEO2DSPHERE, Mongo::GEOHAYSTACK,
# Mongo::TEXT or Mongo::HASHED.
# #
# Note that geospatial indexing only works with versions of MongoDB >= 1.3.3+. Keep in mind, too, # Note that geospatial indexing only works with versions of MongoDB >= 1.3.3+. Keep in mind, too,
# that in order to geo-index a given field, that field must reference either an array or a sub-object # that in order to geo-index a given field, that field must reference either an array or a sub-object
Expand All @@ -501,6 +502,8 @@ def update(selector, document, opts={})
# feature is only available in MongoDB >= 1.3.2. # feature is only available in MongoDB >= 1.3.2.
# @option opts [Boolean] :drop_dups (nil) 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. # this option will keep the first document the database indexes and drop all subsequent with duplicate values.
# @option opts [Integer] :bucket_size (nil) For use with geoHaystack indexes. Number of documents to group
# together within a certain proximity to a given longitude and latitude.
# @option opts [Integer] :min (nil) specify the minimum 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. # @option opts [Integer] :max (nil) specify the maximum longitude and latitude for a geo index.
# #
Expand All @@ -525,11 +528,12 @@ def update(selector, document, opts={})
# #
# @core indexes create_index-instance_method # @core indexes create_index-instance_method
def create_index(spec, opts={}) def create_index(spec, opts={})
opts[:dropDups] = opts[:drop_dups] if opts[:drop_dups] opts[:dropDups] = opts[:drop_dups] if opts[:drop_dups]
field_spec = parse_index_spec(spec) opts[:bucketSize] = opts[:bucket_size] if opts[:bucket_size]
opts = opts.dup field_spec = parse_index_spec(spec)
name = opts.delete(:name) || generate_index_name(field_spec) opts = opts.dup
name = name.to_s if name name = opts.delete(:name) || generate_index_name(field_spec)
name = name.to_s if name
generate_indexes(field_spec, name, opts) generate_indexes(field_spec, name, opts)
name name
end end
Expand All @@ -551,11 +555,12 @@ def create_index(spec, opts={})
# #
# @return [String] the name of the index. # @return [String] the name of the index.
def ensure_index(spec, opts={}) def ensure_index(spec, opts={})
now = Time.now.utc.to_i now = Time.now.utc.to_i
opts[:dropDups] = opts[:drop_dups] if opts[:drop_dups] opts[:dropDups] = opts[:drop_dups] if opts[:drop_dups]
field_spec = parse_index_spec(spec) opts[:bucketSize] = opts[:bucket_size] if opts[:bucket_size]
name = opts[:name] || generate_index_name(field_spec) field_spec = parse_index_spec(spec)
name = name.to_s if name name = opts[:name] || generate_index_name(field_spec)
name = name.to_s if name


if !@cache[name] || @cache[name] <= now if !@cache[name] || @cache[name] <= now
generate_indexes(field_spec, name, opts) generate_indexes(field_spec, name, opts)
Expand Down Expand Up @@ -1017,11 +1022,13 @@ def parse_index_spec(spec)
end end
elsif spec.is_a?(Array) && spec.all? {|field| field.is_a?(Array) } elsif spec.is_a?(Array) && spec.all? {|field| field.is_a?(Array) }
spec.each do |f| spec.each do |f|
if [Mongo::ASCENDING, Mongo::DESCENDING, Mongo::GEO2D, Mongo::GEOHAYSTACK].include?(f[1]) if Mongo::INDEX_TYPES.include?(f[1])
field_spec[f[0].to_s] = f[1] field_spec[f[0].to_s] = f[1]
else else
raise MongoArgumentError, "Invalid index field #{f[1].inspect}; " + raise MongoArgumentError, "Invalid index field #{f[1].inspect}; " +
"should be one of Mongo::ASCENDING (1), Mongo::DESCENDING (-1) or Mongo::GEO2D ('2d')." "should be one of Mongo::ASCENDING (#{Mongo::ASCENDING}), Mongo::DESCENDING (#{Mongo::DESCENDING}), " +
"Mongo::GEOHAYSTACK ('#{Mongo::GEOHAYSTACK}'), Mongo::GEO2DSPHERE ('#{Mongo::GEO2DSPHERE}'), " +
"Mongo::TEXT ('#{Mongo::TEXT}'), or Mongo::HASHED ('#{Mongo::HASHED}')"
end end
end end
else else
Expand Down Expand Up @@ -1109,8 +1116,8 @@ def insert_documents(documents, collection_name=@name, check_keys=true, write_co


def generate_index_name(spec) def generate_index_name(spec)
indexes = [] indexes = []
spec.each_pair do |field, direction| spec.each_pair do |field, type|
indexes.push("#{field}_#{direction}") indexes.push("#{field}_#{type}")
end end
indexes.join("_") indexes.join("_")
end end
Expand Down
2 changes: 1 addition & 1 deletion lib/mongo/db.rb
Expand Up @@ -441,7 +441,7 @@ def drop_index(collection_name, index_name)
# #
# @param [String] collection_name # @param [String] collection_name
# #
# @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, type] 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)}
Expand Down
24 changes: 24 additions & 0 deletions test/functional/collection_test.rb
Expand Up @@ -1252,12 +1252,36 @@ def test_max_scan
assert_nil @geo.index_information['baz'] assert_nil @geo.index_information['baz']
end end


#should "create a text index" do
# @geo.save({'title' => "some text"})
# @geo.create_index([['title', Mongo::TEXT]])
# assert @geo.index_information['title_text']
#end

should "create a hashed index" do
@geo.save({'a' => 1})
@geo.create_index([['a', Mongo::HASHED]])
assert @geo.index_information['a_hashed']
end

should "create a geospatial index" do should "create a geospatial index" do
@geo.save({'loc' => [-100, 100]}) @geo.save({'loc' => [-100, 100]})
@geo.create_index([['loc', Mongo::GEO2D]]) @geo.create_index([['loc', Mongo::GEO2D]])
assert @geo.index_information['loc_2d'] assert @geo.index_information['loc_2d']
end end


should "create a geoHaystack index" do
@geo.save({ "_id" => 100, "pos" => { "long" => 126.9, "lat" => 35.2 }, "type" => "restaurant"})
@geo.create_index([['pos', Mongo::GEOHAYSTACK], ['type', Mongo::ASCENDING]], :bucket_size => 1)
puts @geo.index_information['loc_geoHaystack_type_1']
end

should "create a geo 2dsphere index" do
@collection.insert({"coordinates" => [ 5 , 5 ], "type" => "Point"})
@geo.create_index([['coordinates', Mongo::GEO2DSPHERE]])
assert @geo.index_information['coordinates_2dsphere']
end

should "create a unique index" do should "create a unique index" do
@collection.create_index([['a', Mongo::ASCENDING]], :unique => true) @collection.create_index([['a', Mongo::ASCENDING]], :unique => true)
assert @collection.index_information['a_1']['unique'] == true assert @collection.index_information['a_1']['unique'] == true
Expand Down
2 changes: 1 addition & 1 deletion test/unit/collection_test.rb
Expand Up @@ -106,7 +106,7 @@ class CollectionTest < Test::Unit::TestCase
@coll.ensure_index [["x", Mongo::DESCENDING]] @coll.ensure_index [["x", Mongo::DESCENDING]]
end end


should "call generate_indexes for a new direction on the same field for ensure_index" do should "call generate_indexes for a new type on the same field for ensure_index" do
@client = MongoClient.new('localhost', 27017, :logger => @logger, :connect => false) @client = MongoClient.new('localhost', 27017, :logger => @logger, :connect => false)
@db = @client['testing'] @db = @client['testing']
@coll = @db.collection('books') @coll = @db.collection('books')
Expand Down

0 comments on commit 6b80321

Please sign in to comment.