3

我有一个

class Item
  include Mongoid::Document
  field name, type: String
end

和一个

class Pack
  include Mongoid::Document
end

每个包可以包含不同数量的不同项目。

我最初想做

class Pack
  include Mongoid::Document

  field items, type: Array
end

起初,我尝试

a = Pack.new
a.items = []
a.items << {item: Item.first, quantity: 4}
a.save

我得到了:

NoMethodError: undefined method `__bson_dump__' for #<Item:0x007faf1a56d670>

然后我尝试了:

a = Pack.new
a.items = []
a.items << {item_id: Item.first.id, quantity: 4}
a.save

但现在我不能做类似的事情

a.items[0].item.name

接下来,我尝试了

class Item
  include Mongoid::Document
  field name, type: String
  belongs_to :item_quantity
end

class ItemQuantity
  include Mongoid::Document
  has_one :item
  belongs_to :pack
  field quantity, type: Integer
end

class Pack
  include Mongoid::Document
  has_many :item_quantity
end

哪个有效,但感觉像一个杂物

我怎样才能最好地做到这一点?

4

1 回答 1

2

您的最后一次迭代与我过去解决类似问题的方式接近。我会尽量适应你的情况。我所做的主要不同之处在于不将数量存储在“加入”集合中,因此对于包中项目的多个“副本”中的每一个,都会在该集合中创建一个新文档。

class Item
  include Mongoid::Document
  has_many :item_instances
end

class ItemInstance
  include Mongoid::Document
  belongs_to :item
  belongs_to :pack
end

class Pack
  include Mongoid::Document
  has_many :item_instances      
end

有了这个,您可以执行以下操作:

pack = Pack.new
item = Item.first
pack.item_instances.build(item_id: item.id)

我已经将它用于类所在的印刷店管理应用程序Invoice, Job, Product。一份工作是一种产品的“实例”,一张发票有很多工作,可能都是同一种产品,所以直接的多对多映射是行不通的。

我还会重新考虑您的架构并确保有意义地命名事物。只需将您的类从分别重命名Item, ItemInstance, PackProduct, Item, Pack,就可以使事情变得更加清晰:

pack = Pack.new
product = Product.first
pack.items.build(product_id: product.id)

最后,如果您在Pack类中创建一些简单的便捷方法,那么对于创建更有用的接口大有帮助:

class Pack
  def new_item(product)
    self.items.build(product_id: product.id)
  end

  def products
    self.items.map { |i| i.product }
  end
end

所以你可以这样做:

pack.add_item(product)
# Same as using pack.items.build(product_id: product.id)

pack.products
# Returns an array (including duplicates) of all the products included in the pack.

希望有帮助。这并不经常出现,我确信还有其他解决方案,但这是我在尝试解决“一个对象具有多个对象”问题时使用的基本模式。

添加与您将如何使用该类相关的您自己的方法,它应该非常有用。另外,不要忘记在“join”集合上设置索引。并在 Mongoid 的 Github 页面上查看此问题,请求用于多对多关系的数组中的多个条目。

如果添加了它,那么如果您只需要一个简单的关系,这将是未来的方式。如果您要存储更多详细信息,就像我在创建产品的打印作业时所做的那样(时间戳、标题等),您仍然需要执行上述操作。

于 2012-09-23T06:47:25.757 回答