Join us at MongoDB.local London on 7 May to unlock new possibilities for your data. Use WEB50 to save 50%.
Register now >
Docs 菜单
Docs 主页
/ /
/ / /

模型关系和非规范化

在本指南中,您可以学习;了解如何在 Django MongoDB后端中对集合之间的关系进行建模。由于MongoDB是一个文档数据库,因此 Django MongoDB后端提供了嵌入式模型字段,可将相关数据存储在单个文档中,而不是跨多个集合。 Django MongoDB后端还提供了一个大量字段,允许您在父文档中存储相关标量值的列表。

本指南解释了何时使用每种方法,并提供了示例来演示这些策略。

本指南中的示例定义的模型表示 sample_mflix数据库中的以下集合:

  • movies:存储有关电影的信息

  • embedded_movies:使用矢量图嵌入扩展 movies

  • users:存储有关电影观众的信息

  • comments:存储有关电影评论的信息

sample_mflix要学习;了解有关 数据库的更多信息,请参阅MongoDB Atlas文档中的 示例 Mflix 数据集。

关系数据库将数据规范化到单独的表中,并在查询时使用联接来组合相关数据。 MongoDB 的文档模型允许您将相关数据直接嵌入到父文档中,这称为非规范化。 Django MongoDB后端支持这两种方法,但我们建议您对数据进行非规范化以获得更好的性能。

要进行非规范化,请选择以下策略之一:

  • 嵌入相关模型:使用EmbeddedModelFieldEmbeddedModelArrayField 将相关数据存储在父文档中。嵌入式数据与父文档存储在同一MongoDB文档中,并在单个读取操作中检索。

  • 存储数组数据:使用 将相关标量值列表直接存储在父文档中。在单个读取操作中检索数组数据,无需ArrayField $lookup操作。

当应用以下所有条件时,请使用嵌入式模型:

  • 相关数据始终与父文档一起读取。

  • 相关数据属于单个父文档,不会在多个文档之间共享。

  • 相关项目的数量是有限且可预测的。

要嵌入相关数据,请将嵌入式模型类定义为EmbeddedModel 的子类,然后使用 EmbeddedModelField 将其存储在父模型中。

以下示例定义了一个 Director 嵌入式模型,然后定义了一个存储 Director 模型实例的 Movie 模型:

from django.db import models
from django_mongodb_backend.models import EmbeddedModel
from django_mongodb_backend.fields import EmbeddedModelField
class Director(EmbeddedModel):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
class Movie(models.Model):
title = models.CharField(max_length=200)
director = EmbeddedModelField(Director, null=True, blank=True)

要学习;了解有关嵌入式模型的更多信息,请参阅创建模型指南中的 存储嵌入式模型数据。

使用 ArrayField 将相关标量值的列表直接存储在父文档中。数组数据存储在同一个MongoDB文档中,并在单个读取操作中检索,而无需执行$lookup 操作。当应用以下条件时,请使用此策略:

  • 相关值是简单标量,例如字符串或整数。

  • 大量大小是有界且可预测的。

以下示例定义了一个 Movie 模型,用于在 cast字段中存储字符串列表:

from django.db import models
from django_mongodb_backend.fields import ArrayField
class Movie(models.Model):
title = models.CharField(max_length=200)
cast = ArrayField(models.CharField(max_length=100), blank=True)

要存储结构化文档数组而不是标量值,请改用 EmbeddedModelArrayField。要学习;了解更多信息,请参阅创建模型指南中的存储嵌入式模型数组数据。

重要

如果您的数据结构类似于关系数据库,并且您需要对大型分层数据集进行建模,则可以使用以下关系 Django 字段来链接不同集合中的文档:

重要

您不能在嵌入式模型类中使用关系字段,也不能将其用作 ArrayFieldbase_field

使用ForeignKey 字段在两个模型之间创建多对一关系。引用模型中的每个文档都链接到被引用模型中的一个文档。将以下参数传递给ForeignKey() 构造函数:

  • to:要链接到的模型类

  • on_delete:删除引用文档时的删除行为

以下示例使用 ForeignKey字段将 Comment 模型链接到 Movie 模型。删除sample_mflix.movies文档时,所有相关的 sample_mflix.comments 文档也会被删除:

from django.db import models
class Movie(models.Model):
title = models.CharField(max_length=200)
class Comment(models.Model):
movie = models.ForeignKey(
Movie,
on_delete=models.CASCADE,
)
text = models.TextField()

提示

要学习;了解有关on_delete 选项的更多信息,请参阅 Django 文档中的ForeignKey.on_delete。

使用OneToOneField 字段在两个模型之间创建一对一关系。引用模型中的每个文档都链接到被引用模型中的一个文档。将以下参数传递给OneToOneField() 构造函数:

  • to:要链接到的模型类

  • on_delete:删除引用的文档时的删除行为

以下示例定义了一个 EmbeddedMovie 模型,该模型使用 OneToOneField字段链接到 Movie 模型。删除sample_mflix.movies文档时,其链接的 sample_mflix.embedded_movies文档也会被删除:

from django.db import models
from django_mongodb_backend.fields import ArrayField
class Movie(models.Model):
title = models.CharField(max_length=200)
class EmbeddedMovie(models.Model):
movie = models.OneToOneField(
Movie,
on_delete=models.CASCADE,
)
plot_embedding = ArrayField(models.FloatField(), blank=True)

使用ManyToManyField 字段在两个模型之间创建多对多关系。任一模型中的每个文档都可以链接到另一个模型中的多个文档。将要链接的模型类作为第一个参数传递给ManyToManyField() 构造函数。

以下示例将 Viewer 模型链接到 Movie 模型。每个观看者可以观看多部电影,并且每部电影可以由多个观看者观看:

from django.db import models
class Movie(models.Model):
title = models.CharField(max_length=200)
class Viewer(models.Model):
name = models.CharField(max_length=100)
email = models.CharField(max_length=200)
watched = models.ManyToManyField(Movie, blank=True)

如果您有使用关系字段的现有模型并希望提高读取性能,则可以将其转换为使用嵌入式模型。这样就消除了 $lookup 操作,并将所有相关数据存储在单个MongoDB文档中。

此示例定义了一个具有以下关系字段的 Movie 模型:

from django.db import models
class Director(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
class Award(models.Model):
wins = models.IntegerField(default=0)
nominations = models.IntegerField(default=0)
text = models.CharField(max_length=100)
class Writer(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
class Movie(models.Model):
title = models.CharField(max_length=200)
director = models.ForeignKey(
Director,
null=True,
on_delete=models.SET_NULL,
)
awards = models.OneToOneField(
Award,
null=True,
on_delete=models.SET_NULL,
)
writers = models.ManyToManyField(Writer, blank=True)

要将这些关系字段转换为嵌入式字段,请更改每个相关模型以扩展 EmbeddedModel 而不是 models.Model,然后将 Movie 模型的关系字段替换为相应的嵌入式字段:

  • ForeignKey 替换为 EmbeddedModelField

  • OneToOneField 替换为 EmbeddedModelField

  • ManyToManyField 替换为 EmbeddedModelArrayField

以下示例显示了转换后的 Movie 模型:

from django.db import models
from django_mongodb_backend.models import EmbeddedModel
from django_mongodb_backend.fields import (
EmbeddedModelField,
EmbeddedModelArrayField,
)
class Director(EmbeddedModel):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
class Award(EmbeddedModel):
wins = models.IntegerField(default=0)
nominations = models.IntegerField(default=0)
class Writer(EmbeddedModel):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
class Movie(models.Model):
title = models.CharField(max_length=200)
director = EmbeddedModelField(Director, null=True, blank=True)
awards = EmbeddedModelField(Award, null=True, blank=True)
writers = EmbeddedModelArrayField(Writer, blank=True)

要学习;了解如何跨相关模型查询数据,请参阅指定查询指南中的高级字段查询。

要学习;了解有关 Django 关系字段的更多信息,请参阅 Django 文档中的模型字段参考。

要学习;了解有关嵌入式模型的更多信息,请参阅创建模型指南中的存储嵌入式模型数据。

后退

地理空间模型

在此页面上