marvwhere
marvwhere

Reputation: 571

Find entries where a Hash field includes a given value

I have a field in my mongo database with a hash value, example:

Company.find('testCompany').categories
=> {"architects"=>"architects", "landscape_designers"=>"landscape_designers"}

How can i do a .where select on this field? So i can find entries by single categories? Like i search my database for "landscape_designers" and get all entries who have it included in there categories hash

I found something like

Company.where(:'categories.landscape_designers'.gt => 0)

but it is not working.

thanks in advance!

Upvotes: 1

Views: 1451

Answers (2)

mu is too short
mu is too short

Reputation: 434665

If the key and value in the categories Hash are always the same then:

Company.where('categories.landscape_designers' => 'landscape_designers')

should do the trick. If you just want to see if there's a landscape_designers key in categories then you could use $exists:

Company.where(:'categories.landscape_designers'.exists => true)
Company.where('categories.landscape_designers' => { :$exists => true })

Note that:

$exists does match documents that contain the field that stores the null value.

so $exists will match :categories => { :landscape_designers => nil }. If you want to exclude that pathological case then:

Company.where(:'categories.landscape_designers'.ne => nil)
Company.where('categories.landscape_designers' => { :$ne => nil })

In any case, I think you a design problem with your schema. Your categories appear to be a set rather than a Hash so you're confusing the fields logical type with its implementation. You could use an Array instead of a Hash and let MongoDB's multi-keys take care of searching the array; for example, your model would say:

field :categories, :type => Array
# and maybe some uniqueness validation or cleanup

and then you could treat the array as a scalar in your searches:

Company.where(:categories => 'landscape_designers')

Then MongoDB will unwrap the array for you.

You could also monkey patch a couple things into Set:

class Set
  def mongoize
    self.to_a
  end

  def self.demongoize(object)
    self.new(object)
  end

  def self.mongoize(object)
    if(object.is_a?(Set))
      object.mongoize
    else
      object
    end
  end

  def self.evolve(object)
    if(object.is_a?(Set))
      object.mongoize
    else
      object
    end
  end
end

and then use:

field :categories, :type => Set

to get automatic set behavior in Ruby-land and an Array inside MongoDB.

Upvotes: 3

Dheer
Dheer

Reputation: 793

Use this in your Company model

def method_name
   categories.where("landscape_designers > ?", 0)
end

Upvotes: -1

Related Questions