MongoDB和Mongoid - 动态字段

时间:2011-11-14 05:52:47

标签: ruby-on-rails mongodb mongoid

我正在使用MongoDB,但我并没有真正使用它的动态字段功能

  field :fb_followers => Integer
  field :twitter_followers => Integer
  field :twitter_rts => Integer
  field :link_visiting => Integer
  field :reduce_points_per_day => Integer

如何编写此代码,以便每个字段对于模型都是可选的?

4 个答案:

答案 0 :(得分:6)

所以这里有一些特定于Mongoid的信息。首先,请确保allow_dynamic_fields在您的配置中设置为true(默认为true,但总是很好确定。)

对于我的例子,这是世界上最简单的Mongoid类:

class Foobj
  include Mongoid::Document
  field :static_field
end

因此,我们当然可以正常设置static_field

ruby-1.9.2-p290 :012 > f = Foobj.create!(:static_field => 'barbaz!')
 => #<Foobj _id: 4ec1f2eb90a110143b000003, _type: nil, regular_field: nil, static_field: "barbaz!">

但是我们不能“动态”做一个动态领域,因为Mongoid还不知道它。

ruby-1.9.2-p290 :013 > f.dynamic_field = "hi"
NoMethodError: undefined method `dynamic_field=' for #<Foobj:0x000000044e7ee8>

但是,我可以使用write_attribute来编写动态字段:

ruby-1.9.2-p290 :014 > f.write_attribute(:dynamic_field,"hi!")
 => "hi!"
ruby-1.9.2-p290 :015 > f
 => #<Foobj _id: 4ec1f2eb90a110143b000003, _type: nil, regular_field: nil, static_field: "barbaz!", dynamic_field: "hi!">

而且,现在我已经在Mongoid中“创建”了该字段,我现在可以使用常规机制来访问字段,即使它不在我的类定义中:

ruby-1.9.2-p290 :017 > f.dynamic_field
 => "hi!"

另外,请注意,如果您使用非Mongoid指定的字段加载Mongoid文档,您确实可以以相同的方式访问它们:

ruby-1.9.2-p290 :028 > g = Foobj.first
 => #<Foobj _id: 4ec1f2eb90a110143b000003, _type: nil, regular_field: nil, dynamic_field: "hi!", static_field: "barbaz!">
ruby-1.9.2-p290 :029 > g.dynamic_field
 => "hi!"

但是,使用动态字段最安全的方法是使用write_attributeread_attribute(或其快捷键[]=[]),因为这些不会引发{如果该字段不存在,则为{1}}。

希望有所帮助。当你习惯它时,它真的很简单。有关详细信息,请参阅:http://mongoid.org/docs/documents/dynamic.html

答案 1 :(得分:2)

正如@rubish所说,除了_id之外,MongoDB中的所有字段在MongoDB中都是可选的(除非您使用的是上限集合,在这种情况下,所有字段都是可选的)。

要保存此类记录而不使用这些字段,您可以执行以下操作:

insert({ "some_field_not_related_to_others": 456 })

然后用这些字段保存记录(不需要全部都可以选择字段):

insert({ "fb_followers": 1, "twitter_follower": 2, "twitter_rts": 5 //etc })

MongoDB将以您在insert语句中提供的任何格式保存记录,因为它是无模式的(更多信息可以在这里找到:http://en.wikipedia.org/wiki/NoSQL)。

这意味着每一行都独立于上一行,并且任何标准化的nessecarity都可以携带一定数量的行或字段。

因此,“定义它们是可选的”,你只是不插入它们。

如果这不能回答问题,也许你可以更具体地说明你的意思是“可选”,因为我注意到这是一个红宝石问题所以你可能希望在那里使它成为可选的而不是将其标记为可选的DB。

答案 2 :(得分:2)

只是在控制台中玩一些游戏来说明我的意思“它们是可选的,直到你写一些验证来检查它们的存在。”:

class Stat
  include Mongoid::Document

  field :fb_followers, :type => Integer
  field :twitter_followers, :type => Integer
  field :twitter_rts, :type => Integer
  field :link_visiting, :type => Integer
  field :reduce_points_per_day, :type => Integer
end

pry(main)> Stat.create(:fb_followers => 15).as_document
#=> {"fb_followers"=>15, "_id"=>BSON::ObjectId('4ec1ff1a75f38e676400000d')}
pry(main)> Stat.create(:fb_followers => 15, :twitter_rts => 30).as_document
#=> {"fb_followers"=>15, "twitter_rts"=>30, "_id"=>BSON::ObjectId('4ec1ff2b75f38e676400000e')}
pry(main)> Stat.create(:fb_followers => 15, :twitter_followers => 30).as_document
#=> {"fb_followers"=>15, "twitter_followers"=>30, "_id"=>BSON::ObjectId('4ec1ff4775f38e676400000f')}

Mongodb文档大多看起来像as_document的输出。未设置值的键未设置,请勿在mongodb中设置。我希望能回答这个问题。

答案 3 :(得分:0)

class Foo
  include Mongoid::Document

  field :abc, :type => Integer
end

如果你想再添加一个字段:xyz,那么你可以使用下面的语法。

irb(main):005:0> foo = Foo.new
irb(main):006:0> foo.abc = 1
irb(main):009:0> foo["xyz"] = 2  #dynamic field
irb(main):010:0> foo
=> #<Foo _id: 51f23eebd1d872be84000001, abc: 1, xyz: 2>