Overview
Mongoid 中的关联允许您在模型之间创建关系。在本指南中,您可以学习;了解如何使用嵌入式关联在同一集合中存储不同类型的文档。 Mongoid 支持与以下宏的嵌入式关联:
embeds_oneembeds_manyembedded_inrecursively_embeds_onerecursively_embeds_many
以下各节介绍如何使用这些关联类型。
嵌入一个
要指定类模型包含不同类类型的嵌入式文档,请在父类中使用 embeds_one 宏,并在嵌入式类中使用 embedded_in 宏。 以下示例创建了一个带有嵌入式 Label 类的 Band 类:
class Band include Mongoid::Document embeds_one :label end class Label include Mongoid::Document field :name, type: String embedded_in :band end
Mongoid 将嵌入 embeds_one 宏的文档存储在父文档中,作为与嵌入式类同名的字段。 前面的 Label 文档存储在 Band文档中,如以下示例所示:
# Band document { "_id" : ObjectId("..."), "label" : { "_id" : ObjectId("..."), "name" : "Periphery", } }
您可以使用 store_as 选项以其他名称存储嵌入式文档,如以下示例所示:
class Band include Mongoid::Document embeds_one :label, store_as: "record_label" end
嵌入许多
要指定类模型包含不同类类型的多个嵌入式文档,请在父类中使用 embeds_many 宏,并在嵌入式类中使用 embedded_in 宏。 以下示例创建了一个包含多个嵌入式 Album 类型文档的 Band 类:
class Band include Mongoid::Document embeds_many :albums end class Album include Mongoid::Document field :name, type: String embedded_in :band end
Mongoid 将嵌入 embeds_many 宏的文档存储在父文档中作为与嵌入式类同名的大量字段。 前面的 Album 文档存储在 Band文档中,如以下示例所示:
{ "_id" : ObjectId("..."), "albums" : [ { "_id" : ObjectId("..."), "name" : "Omega", } ] }
您可以使用 store_as 选项以其他名称存储嵌入式文档,如以下示例所示:
class Band include Mongoid::Document embeds_many :albums, store_as: "records" end
递归嵌入
您可以使用 recursively_embeds_one 和 recursively_embeds_many 宏将一个或多个相同类型的文档嵌入到父类中。 这两个宏都通过 parent_* 方法和 child_* 方法为父文档和子文档提供访问器,其中 * 表示类的名称。 以下示例创建了一个 Band 类,该类以递归方式嵌入多个其他 Band 文档来表示多个乐队名称:
class Band include Mongoid::Document field :name, type: String recursively_embeds_many end
您可以通过 parent_band 和 child_band 方法访问权限父文档和子文档,如以下示例所示:
root = Band.new(name: "Linkin Park") # Add child bands child_one = root.child_band.build(name: "Lincoln Park") child_two = root.child_band.build(name: "Xero") # Access parent band child_one.parent_band # Outputs: root
查询嵌入式关联
您可以在使用点表示法查询父类集合时访问权限嵌入式文档。
以下示例使用点表示法查询嵌入 Band 类中的 Tour 类型文档。 此查询返回 tours.year 值为 2000 或更大的文档:
Band.where('tours.year' => {'$gte' => 2000})
您可以使用 pluck投影方法来检索嵌入式文档,而无需检索其关联的父文档,如以下示例所示:
# Get awards for bands that have toured since 2000 Band.where('tours.year' => {'$gte' => 2000}).pluck(:awards)
您可以使用 Mongoid查询方法执行嵌入式匹配,这样您就可以查询已加载到应用程序中的文档的嵌入式关联。Mongoid 实现嵌入式匹配,无需向服务器发送查询。
嵌入式匹配支持以下查询符:
以下示例使用 $gte操作符查询加载的 Band文档的嵌入式 tours字段:
band = Band.where(name: 'Astral Projection').first tours = band.tours.where(year: {'$gte' => 2000})
对已加载文档的嵌入式匹配具有以下已知限制:
以下功能未实现嵌入式匹配:
执行JavaScript代码的操作符,例如 $where
通过其他服务器功能实现的操作符,例如 $expr 和 $jsonSchema
Mongoid 将
Range参数扩展为具有$gte和$lte条件的哈希值。 在某些情况下,这可能会导致无效查询并引发InvalidQuery异常。使用
$regex操作符时,您无法在将正则表达式对象指定为模式的同时为$options字段提供选项。 仅当正则表达式模式是字符串时才能提供选项。
省略_id字段
默认下,Mongoid 会向嵌入式文档添加一个 _id字段。 您可以通过在模型中显式指定 _id字段并默认默认值,从嵌入式文档中省略此字段。 以下示例指示 Mongoid 不要将 _id字段添加到 Albums 类中:
class Album include Mongoid::Document field :name, type: String field :_id, type: Object embedded_in :band end
在前面的 Albums 类中,不会自动添加 _id字段。 如果没有默认值,Mongoid 不会将该值存储在数据库中,除非您在模型中提供默认值。
删除嵌入式关联
您可以使用以下方法之一从 embeds_many 关联中删除子文档:
cleardelete_alldestroy_all
clear方法使用 $unset操作符操作符从父文档中删除整个嵌入式关联。clear 方法不会运行任何 destroy 回调。 以下示例使用 clear 方法从 Band 类中删除所有嵌入式关联:
band = Band.find(...) band.tours.clear
delete_all方法使用 $pullAll操作符操作符删除嵌入式关联中的文档。delete_all 加载关联(如果尚未加载),然后只删除应用程序中存在的文档。 delete_all 方法不会运行任何 destroy 回调。 以下示例使用 delete_all 方法从 Band 类中删除所有嵌入的 Album 文档:
band = Band.find(...) band.tours.delete_all
destroy_all方法还使用 $pullAll操作符操作符删除嵌入式关联中的文档。它还运行在关联文档上定义的任何 destroy 回调。 以下示例使用 destroy_all 方法从 Band 类中删除所有嵌入的 Album 文档:
band = Band.find(...) band.tours.destroy_all