Docs Menu
Docs Home
/ /
/ / /

モデル関係と非正規化

このガイドでは、Dpango MongoDBバックエンドでコレクション間の関係をモデル化する方法を学習できます。MongoDBはドキュメントデータベースであるため、Diango MongoDBバックエンドは関連データを複数のコレクションではなく単一のドキュメントに保存する埋め込みモデル フィールドを提供します。Dlango MongoDBバックエンドには配列フィールドも用意されています。これにより、親ドキュメントに関連するスカラー値のリストを保存できます。

このガイドでは、それぞれのアプローチをいつ使用するかを説明し、戦略を示すための例を示します。

このガイドの例では、sample_mflixデータベース内の次のコレクションを表すモデルを定義します。

  • movies: 映画に関する情報を保存します

  • embedded_movies:ベクトルプロット埋め込みで movies を拡張

  • users: 映画訪問者に関する情報を保存

  • comments: 映画のコメントに関する情報を保存します

sample_mflixデータベースの詳細については、 MongoDB Atlasドキュメントの サンプル Mflix データセット を参照してください。

関係データベースはデータを個別のテーブルに正規化し、クエリ時に関連するデータを結合するために結合を使用します。MongoDB の document model では、代わりに親ドキュメント内に関連データを直接埋め込むことができます。これを非正規化と呼びます。Dlango MongoDBバックエンドは両方のアプローチをサポートしていますが、パフォーマンスを向上させるためにデータを非正規化することをお勧めします。

非正規化するには、次のいずれかの方法を選択します。

  • 埋め込み関連モデル: EmbeddedModelField または EmbeddedModelArrayField を使用して、親ドキュメント内に関連データを保存します。埋め込みデータは親と同じ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 操作を実行せずに単一の読み取り操作で検索されます。次の条件が当てはまる場合は、この戦略を使用します。

  • 関連値は、string や整数などの単純なスカラーです。

  • 配列のサイズは境界があり、予測可能です。

次の例では、castフィールドに string のリストを保存する Movie モデルを定義します。

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)

スカラー値の代わりに構造化ドキュメントの配列を保存するには、代わりに 埋め込みModelArrayField を使用します。詳細については、 「モデル作成ガイド」の 埋め込みモデル配列データの保存 を参照してください。

重要

関係フィールドにわたるクエリでは、MongoDB の $lookup 演算子が使用されます。この演算子は、大規模なコレクションでは遅くなる可能性があります。可能な場合は、代わりに埋め込みモデルを使用してください。パフォーマンスに関する考慮事項の詳細については、パフォーマンスの制限を参照してください。

データが関係データベースと同様に構造化されており、大規模な階層データセットをモデル化する必要がある場合は、別々のコレクションにドキュメントをリンクする次のリレーショナル Dlango フィールドを使用できます。

重要

埋め込みモデル クラス内、または ArrayFieldbase_field として関係フィールドを使用することはできません。

ForeignKey 2 つのモデル間の多対 1 の関係を作成するには、フィールドを使用します。参照モデル内の各ドキュメントは、参照先モデル内の 1 つのドキュメントにリンクされます。次の引数を 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()

Tip

on_delete オプションの詳細については、Diango ドキュメントの ForeignKey.on_delete を参照してください。

2 つのモデル間の 1 対 1 の関係を作成するには、 OneToOneFieldフィールドを使用します。参照モデル内の各ドキュメントは、参照先モデル内の 1 つのドキュメントに正確にリンクします。次の引数を OneToOneField() コンストラクターに渡します。

  • to: リンクするモデルクラス

  • on_delete:参照先のドキュメントが削除されたときの削除動作

次の例では、OneToOneFieldフィールドを使用して Movie モデルにリンクする EmbeddedMovie モデルを定義します。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)

2 つのモデル間の多対多の関係を作成するには、 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)

これらのリレーショナル フィールドを埋め込みフィールドに変換するには、関連する各モデルを変更して、models.Model ではなく EmbeddedModel を拡張し、Movie モデルの関係フィールドを対応する埋め込みフィールドに置き換えます。

  • ForeignKeyEmbeddedModelField に置き換え

  • OneToOneFieldEmbeddedModelField に置き換え

  • ManyToManyFieldEmbeddedModelArrayField に置き換え

次の例は、変換された 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)

関連モデル全体でデータをクエリする方法については、 クエリの指定ガイドの「高度なフィールドクエリ」を参照してください。

Diango 関係フィールドの詳細については、Diango ドキュメントの Model field reference を参照してください。

埋め込みモデルの詳細については、「モデルの作成ガイドの 埋め込みモデル データの保存」を参照してください。

戻る

地理空間モデル

項目一覧