Luca G. Soave
Luca G. Soave

Reputation: 12679

Case-insensitive query criteria with MongoID

I have a query criteria which looks for an array of elements ( tags_array ) to match :

User.all_in('watchlists.tags_array' => tags_array)

I'd like the criteria to be CASE-INSENSITIVE, meaning I want it match %w[Ruby Web Framework] as well as %w[RUBY WEB FRAMEWORK] or %w[ruby web framework] and so on ...

Is this possible via mongoid or do I have to use external filter tricks ?

Upvotes: 1

Views: 2423

Answers (4)

germanlinux
germanlinux

Reputation: 2511

In order to managing regexp in mongo request (find , update..)
I do this:
'p' is a variable that stores the name to search

 reg =  /^#{p}$/i
 @db['pgm'].update({'nom' => reg }.... 

Upvotes: 0

Luca G. Soave
Luca G. Soave

Reputation: 12679

Thanks to the support of Jordan and just for tracking purposes (for myself and others as well), I'll post the entire solution.

Yes, Yuriy Goldshtrakh was right, MongoDB still does not support case-insensitive query but MongoID has regex, my only doubt is regarding performance degradation as already said by "mu is too short" but I didn't check until now ... anyway here it is :

 Object.const_set :Competitor, Struct.new(:html_url, :description, :watchers, :forks)
 def self.find_competitors(tags_array)
    competitors = []
    User.all_in('watchlists.tags_array' => tags_array.map{|tag|/^#{tag}/i}).only(:watchlists).each do |u|
     u.watchlists.all_in(:tags_array => tags_array.map{|tag|/^#{tag}/i}).desc(:watchers).each do |wl|
       competitors << Competitor.new(wl.html_url, wl.description, wl.watchers, wl.forks)
     end
    end
    return competitors
 end

No normalization at save/create mongoid level, the tags are saved either upper or lower case.

Normalization (case-insensitive matching of tags) are realized entirely during the nested quering criteria ( it's nested because of embedded one to many model ).

If you have better idea or code, please have a post.

I'd also thanks Luiz K. for answering, even if I'll not follow that way: normalization at data level is too restrictive in my view, loosing semantic and elasticity "user" side (who actually is tagging). Anyway could be a good solution for other requirements.

Many thanks Luca G. Soave

Upvotes: 5

Luiz E.
Luiz E.

Reputation: 7249

This is what i've done:

def create
    @noticia = Noticia.new(params[:noticia])
    @noticia.tags = @noticia.conteudo.html_safe.split(' ')
    @noticia.tags.each_with_index do |tag, index|
      @noticia.tags[index] = @noticia.tags[index].gsub(/<\/?[^>]*>/, "")
    end

i've splitted all noticia's content into 'tags', and downcased they. in my search i do the following:

def buscar
    array = params[:query].split(' ')
    array.each_with_index do |query, index|
      array[index] = array[index].gsub(/<\/?[^>]*>/, "").downcase
    end
    @noticias = Noticia.where(:tags.all => array).paginate(:page => params[:page])
  end

i've downcased my query search too
don't forget to index tags field

Upvotes: 0

Yuriy Goldshtrakh
Yuriy Goldshtrakh

Reputation: 2014

I don't think mongo has support for the non case-sensitive selects, you can either normalize the data by converting it all to a specific case or use regexp finders

Upvotes: 4

Related Questions