Getting hash with symbol as keys for mongo in rails
According to the FAQ, Even though there is a symbol type in Mongo, and you can store symbols in values, the BSON format specifies that keys must be strings.
Search Mongoid hash field by key
Course.where(:'skills_available.52ab84929938c7f966d4f0cc'.ne => nil)
- Only restriction is that it will skip:
{'52ab84929938c7f966d4f0cc' => nil}
Elegant way to stringify keys with Rails and Mongo?
Something along these lines could work. Basically this code redefines Mongoid's field
macro (its setter).
require 'mongoid'
module Stringifier
def field name, args = {}
super # call mongoid implementation
define_method "#{name}=" do |val|
val.stringify_keys! if val && val.respond_to?(:stringify_keys!)
super(val)
end
end
end
class Foo
include Mongoid::Document
extend Stringifier
field :subhash, type: Hash
end
f = Foo.new
f.subhash = {a: 1, b: 2}
puts f.subhash
# >> {"a"=>1, "b"=>2}
This may not be the cleanest implementation, but you get the idea.
setting default hash keys for mongoid hash field
The :default
option can take a lambda as its value. Inside that lambda, self
will be the new instance you're creating. That means that you can (indirectly) call methods to supply defaults:
class Sport
include Mongoid::Document
field :rules, type: Hash, default: lambda { default_rules }
end
class Sport::Football < Sport
private
def default_rules
{ :offside => '', :penalty => '' }
end
end
class Sport::Boxing < Sport
private
def default_rules
{ :biting => 'not allowed except for ears' }
end
end
You don't have to make default_rules
private of course. You'll also want default_rules
in Sport
if you want to instantiate Sport
directly.
You could also use one of the callbacks to set the rules by hand:
class Sport
include Mongoid::Document
field :rules, type: Hash
after_initialize :set_default_rules, :if => :new_record? # Or one of the other callbacks.
end
and subclasses could say self.rules = ...
in their set_default_rules
implementations.
saving and fetching hash in Mongoid Document
What version of Ruby and Mongoid are you using? Accessing hashes in Mongoid objects via symbols works fine in Mongoid 3.0.4 and Ruby 1.9.3. So I can do something like:
@metrics = Metrics.find(params[:id])[:metrics]
@metrics[:users][:year][:male]
or even:
Metrics.find(params[:id])[:metrics][:users][:year][:male]
Also, why not just leave the metrics
field out, then treat instances of the Metrics
class like instances of Hash
? With Mongoid you can dynamically set and get attributes using the standard Ruby Hash symbol syntax without ever "declaring" the fields. With the metrics
field removed:
m = Metric.new
m[:users] = {}
m[:users][:year] = {}
m[:users][:year][:male] = "data"
Additionally, if you need methods to auto-initialize nested hashes, so you can do things like:
m = Metric.new
m[:users][:year][:male] = "data"
you can put all of that logic into the Metrics
class. To get started on that you could try adapting something like the []
and []=
methods from the AutoHash class explained here. That would give you the cleanest interface I think.
Symbols used as Hash keys get converted to Strings when serialized
More than likely this has to do with the ORM you are using to provide the persistance layer for the model. You can probably wrap some_attr
with a method that returns it in the form of a HashWithIndifferentAccess
which you can then access with either strings or arrays. Since you are using Rails, this functionality can be activated by calling the with_indifferent_access
method on the Hash object. (If you have an array of Hash objects, you'll need to call it on each one of course) The method will return the same hash, but then symbol lookups will work.
From your code:
new_hash = MyMongoModel.last.some_attr.with_indifferent_access
new_hash[:a] # Will return the same as new_hash['a']
Hope this helps!
setting mongoid hash field values
The thing with Hash field is, it can be dynamic as much as you want. Therefore to prevent polluting your DB schema with unintended fields caused by bugs in your code this functionality is disabled by default.
No you are not stuck using 2-step updates for your hashes at all!
[],[]= are the shortcuts for read_attribute()
and write_attribute()
and should be used if you don't include Mongoid::Attributes::Dynamic
. If you try to use $set
without enabling dynamic attributes you will get a no-method error because it does not see your dynamic attributes as defined attributes.
If you'll read the source of Mongoid::Attributes::Dynamic then you'd find that this is required to add the dynamic attributes functionality.
To update the values by including Mongoid::Attributes::Dynamic
you need to follow these steps:
thing = Thing.first
thing.set("info.endDate" => Time.now)
thing.reload # This will update the current variable
Otherwise if you need you can easily skip this and do the value update by 2-step method
I hope this sheds some light over your query.
Source:
Rails mongoid dynamic fields - no method error
Dynamic attributes with Rails and Mongoid
Using IN while querying on mongoid hash field
The query methods such as in
and ne
are added to Symbol
, not String
. So you can say:
:'keys.location_id'.in => location_ids
where location_ids
is an array. Also, the query methods are just short forms for building the longer native-style nested Hash queries. For example, if you say:
:field.op => value
for some operator op
, then Mongoid actually sends this (JavaScript) into MongoDB:
field: { $op: value }
So if you don't want to write :'keys.location_id'.in
then you can say:
'keys.location_id' => { :$in => location_ids }
# or
'keys.location_id' => { '$in' => location_ids }
instead.
Also note that if location_ids
is an array then [location_ids]
is an array of arrays and that's not what you want in your query, you want just location_ids
as above.
Related Topics
How to Escape the Vertical Bar When Doing Command Line with Ruby
How to Speed Up Ruby/Rake Task
Currying a Proc with Keyword Arguments in Ruby
How to Turn Off Bigint Primary Keys in Rails 5.1
Ruby Syntax Question: Rational(A, B) and Rational.New!(A, B)
How to Reduce the Quality of an Uploading Image Using Paperclip
How to Fix in Ruby on Rails the Undefined Method 'Alias_Method_Chain' Error
Bundle Install Is Using a Different Ruby Version
Error While Installing Iconv on Windows by Ruby2.0.0
Rmagick How to Convert Image in Memory
How to Get a List from a Ruby Enumerable
Rails: Uninitialized Constant Just Happen on Production Server
Custom To_Yaml and Domain_Type
System New Line Separator in Ruby
How Can Same Program in Ruby Accept Input from User as Well as Command Line Arguments