Make the MongoDB docs better! We value your opinion. Share your feedback for a chance to win $100.
Click here >
Docs 菜单
Docs 主页
/ /

嵌入式关联

Mongoid 中的关联允许您在模型之间创建关系。在本指南中,您可以学习;了解如何使用嵌入式关联在同一集合中存储不同类型的文档。 Mongoid 支持与以下宏的嵌入式关联:

  • embeds_one

  • embeds_many

  • embedded_in

  • recursively_embeds_one

  • recursively_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_onerecursively_embeds_many 宏将一个或多个相同类型的文档嵌入到父类中。 这两个宏都通过 parent_* 方法和 child_* 方法为父文档和子文档提供访问器,其中 * 表示类的名称。 以下示例创建了一个 Band 类,该类以递归方式嵌入多个其他 Band 文档来表示多个乐队名称:

class Band
include Mongoid::Document
field :name, type: String
recursively_embeds_many
end

您可以通过 parent_bandchild_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 实现嵌入式匹配,无需向服务器发送查询。

嵌入式匹配支持以下查询符:

  • 比较操作符

  • 逻辑操作符

  • 数组查询操作符

  • $exists

  • $mod

  • $type

  • $regex

  • 按位操作符

以下示例使用 $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字段提供选项。 仅当正则表达式模式是字符串时才能提供选项。

默认下,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 关联中删除子文档:

  • clear

  • delete_all

  • destroy_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

后退

引用的关联

在此页面上