MongoDB mongoid 的 accepts_nested_attributes_for 怎么用

yakjuly · 2012年01月16日 · 最后由 yakjuly 回复于 2012年02月04日 · 3872 次阅读

最近刚开始在实际项目中用mongodb,遇到一些问题 ,请教一下大家。

class Policy
  include Mongoid::Document

  has_many :buckets
  accepts_nested_attributes_for :buckets

  field :min_device, :type => Integer, :default => 0
  field :max_device, :type => Integer, :default => 10
  field :name
end

class Bucket
  include Mongoid::Document

  belongs_to :policy

  field :start_point, :type => Integer
  field :end_point, :type => Integer  
  field :min, :type => Integer
  field :max, :type => Integer
end
params = {"policy"=>{"name"=>"aaaaaa", "buckets_attributes"=>{"new_1326681393748"=>{"end_point"=>"4", "max"=>"4", "min"=>"1", "_destroy"=>"false", "start_point"=>"1"}, "0"=>{"end_point"=>"11", "max"=>"10", "min"=>"7", "_destroy"=>"false", "start_point"=>"9"}}, "min_device"=>"1", "max_device"=>"4"}}

步骤

@policy = Policy.new(params[:policy])
 => #<Policy _id: , name: "aaaaaa", min_device: 1, _type: nil, max_device: 4>
@policy.buckets
 => [#<Bucket _id: , policy_id: nil, end_point: 4, max: 4, _type: nil, min: 1, start_point: 1>, #<Bucket _id: , policy_id: nil, end_point: 11, max: 10, _type: nil, min: 7, start_point: 9>]
@policy.save
@policy
 => #<Policy _id: 10, name: "aaaaaa", min_device: 1, _type: nil, max_device: 4>
@policy.buckets
 => [#<Bucket _id: , policy_id: nil, end_point: 4, max: 4, _type: nil, min: 1, start_point: 1>, #<Bucket _id: , policy_id: nil, end_point: 11, max: 10, _type: nil, min: 7, start_point: 9>] 

问题

  1. policy关联的buckets为什么都没有关联保存?

搜了stackoverflow后 把 Policy的 has_many :buckets 改成了 has_many :buckets, :autosave => true后. 重试以上步骤

@policy.buckets
 => [#<Bucket _id: 17, policy_id: nil, end_point: 4, max: 4, _type: nil, min: 1, start_point: 1>, #<Bucket _id: 18, policy_id: nil, end_point: 11, max: 10, _type: nil, min: 7, start_point: 9>] 

bucket保存了id,但是policy_id仍然为空,他们的关联关系没有保存下来。为什么,有什么办法解决?

另外还有个小问题,embeds_many embeds_in 和 has_many belongs_to 区别在哪里?

共收到 9 条回复

关于“小问题”http://mongoid.org/docs/relations.html embeds_many是Embedded relations has_many是Referenced relations

Embedded relations are associations between one or many objects where the child object is embedded within the parent in the same document in the database. They can be extremely efficient when kept to a managable size in MongoDB since the total number of queries required to retrieve an entire object graph can be reduced to one.

Referenced relations are associations between documents that reside in separate collections in MongoDB. The link between the documents is handled similar to a relational database where a "foreign key" needs to be stored on one or both sides of the relation, but note that accessing a referenced relation required a separate query to the database since joins cannot be performed.

关于anaf,你的参数和文档里提到的不一致 http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html

params = { :member => {
  :name => 'joe', :posts_attributes => [
    { :title => 'Kari, the awesome Ruby documentation browser!' },
    { :title => 'The egalitarian assumption of the modern citizen' },
    { :title => '', :_destroy => '1' } # this will be ignored
  ]
}}

member = Member.create(params['member'])
member.posts.length # => 2
member.posts.first.title # => 'Kari, the awesome Ruby documentation browser!'
member.posts.second.title # => 'The egalitarian assumption of the modern citizen'

mongoid里也是这种格式http://mongoid.org/docs/relations/nested_attributes.html

简单说,就是你没用数组

@cqpx embeds_many 不知道有什么场景下比较适合, 你能简单介绍一下吗?

我的参数是用 nested_form 插件生成的,里面会带一个 key,我可以试下官方格式的参数。

@cqpx 我把参数改成官方的格式还是不行。

a
 => {"policy"=>{"name"=>"aaaaaa", "buckets_attributes"=>[{"end_point"=>"4", "max"=>"4", "min"=>"1", "_destroy"=>"false", "start_point"=>"1"}, {"end_point"=>"11", "max"=>"10", "min"=>"7", "_destroy"=>"false", "start_point"=>"9"}], "min_device"=>"1", "max_device"=>"4"}} 
p = Policy.new a["policy"]
p.save
p.buckets
 => [#<Bucket _id: 21, policy_id: nil, end_point: 4, max: 4, _type: nil, min: 1, start_point: 1, _destroy: "false">, #<Bucket _id: 22, policy_id: nil, end_point: 11, max: 10, _type: nil, min: 7, start_point: 9, _destroy: "false">] 

在你需要has_one/has_many这样的从属关系,但是又不想再单独为被包含的对象建一个表的时候用。

比如user has_one profile,profile包括name,address,phone等等

你不想单独建一个profile表,但是全部作为User的属性又显得很乱,就可以把profile嵌入到user里面,实际上还在user表里,但是有了has_one/has_many这样的从属关系,逻辑上更清晰

https://github.com/chloerei/code_campo/blob/master/app/models/user.rb https://github.com/chloerei/code_campo/blob/master/app/models/profile.rb

淘宝的User,UserCredit也是这样的关系, http://open.taobao.com/doc/api_cat_detail.htm?cat_id=1&category_id=102 如果淘宝没用mongodb这样的文档型数据库,那么它就必须建一个UserCredit表, 用了mongodb,就可以把UserCredit嵌入到User里

#4楼 @yakjuly 为什么你的policy的_id是数字不是BSON?会不会跟这个有关? 我这里用anaf是可以的https://github.com/cqpx/yakjuly

@cqpx 我是用了 ruby-china的插件

Mongoid 辅助插件

gem 'mongo-rails-instrumentation','0.2.4'

Mongoid 使用自增整形ID

gem 'mongoid_auto_increment_id', "0.3.1"

初步接触mongodb还没有看他们插件的实现。 你这么一提醒 很可能是插件的实现有问题。

可以试试用codecampo实现自增id的方法看行不行,这个方法就不会覆盖mongoid默认的BSON格式,而是另外加一个field来数数 https://github.com/chloerei/code_campo/blob/master/app/models/user.rb https://github.com/chloerei/code_campo/blob/master/app/models/mongoid/number_id.rb

@cqpx

可以试试,看了下 number_id 解决了自增id的问题,但还是没有解决自动设置外键关联的问题。 如果可以增强一下number_id 自动根据关联对象 给 外键field赋值,就比较好用了。

谢谢你,这么热心回答问题。

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册