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

引用的关联

Mongoid 中的关联允许您在模型之间创建关系。在本指南中,您可以学习;了解引用关联如何允许您在两个模型之间创建一种关系,其中一个模型引用另一个模型。 Mongoid 支持以下引用关联类型:

  • has_one

  • has_many

  • belongs_to

  • has_and_belongs_to_many

以下部分描述了如何使用每种关联类型。

您可以使用 has_one 宏来声明由一个类表示的文档也包含由单独的子类表示的文档。 以下示例创建了一个与 Studio 类具有 has_one关系的 Band 类:

class Band
include Mongoid::Document
has_one :studio
end

当您声明 has_one 关联时,子类还必须使用引用父类的 belongs_to 关联。 以下示例显示了前面的 Band 类中引用的 Studio 类:

class Studio
include Mongoid::Document
belongs_to :band
end

要学习;了解有关belongs_to 宏的详情,请参阅 属于部分。

您可以使用验证来确保子类存在于父类中,如以下示例所示:

class Band
include Mongoid::Document
has_one :studio
validates_presence_of :studio
end

要学习;了解有关 Mongoid 中验证的更多信息,请参阅 验证指南。

您可以使用 has_many 宏来声明一个类表示的文档包含由另一个类表示的多个子文档。 以下示例创建了一个与 Members 类具有 has_many关系的 Band 类:

class Band
include Mongoid::Document
has_many :members
end

当您声明 has_many 关联时,子类还必须使用引用父类的 belongs_to 关联。 以下示例显示了前面的 Band 类中引用的 Member 类:

class Member
include Mongoid::Document
belongs_to :band
end

要学习;了解有关belongs_to 宏的更多信息,请参阅“属于”部分。

您可以使用验证来确保子类存在于父类中,如以下示例所示:

class Band
include Mongoid::Document
has_many :members
validates_presence_of :members
end

要学习;了解有关 Mongoid 中验证的更多信息,请参阅 验证指南。

您可以对 has_many 关联使用 any? 方法,以确定该关联是否包含任何文档,而无需从数据库中检索整个文档设立。

以下示例使用 any? 方法来确定 Band 类中的文档是否包含任何 Members 文档:

band = Band.first
band.members.any?

您还可以使用带有过滤的 any? 方法来查找与指定条件匹配的文档,如以下示例所示:

band = Band.first
band.members.any? { |member| member.instrument == 'piano' }

您可以向 any? 方法提供类名,以按类名过滤结果。 这对于多态关联非常有用:

class Drummer < Member
end
band = Band.first
band.members.any?(Drummer)

注意

将关联类的数据加载到 Mongoid 后,对 any? 方法的后续调用不会查询数据库。 相反,Mongoid 使用已加载到内存中的数据。

您还可以调用 exists? 方法来确定关联中是否有任何持久化文档。 exists? 方法始终查询数据库并仅检查已保存到数据库的文档。 exists? 方法不允许过滤,也不接受任何参数。

以下示例使用 exists? 方法来确定 Band 类中是否存在任何持久的 Members 文档:

band = Band.create!
# Member is not persisted.
band.members.build
band.members.exists?
# Outputs: false
# Persist the member
band.members.map(&:save!)
band.members.exists?
# Outputs: true

使用 belongs_to 宏声明一个类表示的文档是另一个类表示的文档的子文档。 默认下,父类的 _id字段存储在子类中。 以下示例创建一个 Members 类,其中包含与 Band 类的 belongs_to 关联:

class Members
include Mongoid::Document
belongs_to :band
end

您可以通过将 optional 选项设置为 true,允许 Mongoid 将文档持久保存到数据库,而不存储关联父类的 _id,如以下示例所示:

class Members
include Mongoid::Document
belongs_to :band, optional: true
end

提示

通过在应用程序的配置设置中将 belongs_to_required_by_default 配置选项设置为 false,您可以全局更改 belongs_to 关联的默认行为,以便不需要其父类。

您可以在子类中指定 belongs_to 关联,而无需在父类中指定匹配的 has_onehas_many 关联。 这样做时,您无法从父类访问权限子文档的字段,但可以访问权限存储在子类中的父字段,例如父文档的 _id字段。 在以下示例中,Band 类无法访问权限Members 类,但 Members 类可以访问权限Band 类:

class Band
include Mongoid::Document
end
class Members
include Mongoid::Document
belongs_to :band
end

为清楚起见,您可以选择将 inverse_of 选项设立为 nil,以指示父类不包含与子类的 has_onehas_many 关联,如以下示例所示:

class Band
include Mongoid::Document
end
class Members
include Mongoid::Document
belongs_to :band, inverse_of: nil
end

使用 has_and_belongs_to_many 宏声明类模型包含与另一个类的多对多关系。 在多对多关系中,一个类中的每个文档都可以与另一个类中的多个文档相关联。 以下示例创建了一个与 Members 类具有 has_and_belongs_to_many关系的Band 类。 一个 Band文档可以引用多个 Members 文档,一个 Members文档可以引用多个 Band 文档。

class Band
include Mongoid::Document
has_and_belongs_to_many :members
end
class Members
include Mongoid::Document
has_and_belongs_to_many :bands
end

当您声明 has_and_belongs_to_many 关联时,两个模型实例存储关联文档的 _id 值的列表。 您可以将 inverse_of 选项设立为 nil,以将关联文档的 _id 值仅存储在一个模型实例中。 以下示例提示 Mongoid 将关联文档的 _id 值仅存储在 Band 类中:

class Band
include Mongoid::Document
has_and_belongs_to_many :tags, inverse_of: nil
end
class Tag
include Mongoid::Document
end

提示

当您更新具有 has_and_belongs_to_many 关联的文档时,Mongoid 会设置更新文档的 updated_at字段,但不会设立关联文档的 updated_at字段。

您可以使用聚合管道跨引用的关联查询文档。 聚合管道允许您跨多个集合创建查询并将数据处理为指定的格式。 要学习;了解有关使用聚合管道的更多信息,请参阅聚合指南。

对于简单的查询,可以直接查询关联。 直接查询集合时,只能查询集合本身中的字段和值。 您无法直接查询与您正在查询的集合关联的集合。

示例,考虑以下 BandTour 类:

class Band
include Mongoid::Document
has_many :tours
field :name, type: String
end
class Tour
include Mongoid::Document
belongs_to :band
field :year, type: Integer
end

以下示例查询 Tour 类中 year 值为 2000 或更大的文档,并保存这些文档的 band_id。 然后,它会在 Band 类中查询具有这些 band_id 值的文档。

band_ids = Tour.where(year: {'$gte' => 2000}).pluck(:band_id)
bands = Band.find(band_ids)

后退

回调

在此页面上