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

Relaciones entre modelos y desnormalización

En esta guía, aprenderá a modelar las relaciones entre colecciones en Django MongoDB Backend. Dado que MongoDB es una base de datos de documentos, Django MongoDB Backend proporciona campos de modelo integrados que almacenan datos relacionados en un único documento, en lugar de distribuirlos entre varias colecciones. Django MongoDB Backend también ofrece un campo de matriz que permite almacenar una lista de valores escalares relacionados en el documento principal.

Esta guía explica cuándo utilizar cada enfoque y proporciona ejemplos para demostrar las estrategias.

Los ejemplos de esta guía definen modelos que representan las siguientes colecciones en la sample_mflix database:

  • moviesAlmacena información sobre películas.

  • embedded_movies: Extiende movies con incrustaciones de gráficos vectoriales

  • usersAlmacena información sobre los espectadores de películas.

  • commentsAlmacena información sobre los comentarios de las películas.

Para obtener más información sobre la base de datos sample_mflix, consulte Consulte el conjunto de datos de ejemplo de Mflix en la documentación de MongoDB Atlas.

Las bases de datos relacionales normalizan los datos en tablas separadas y utilizan uniones para combinar datos relacionados en el momento de la consulta. El modelo de documentos de MongoDB permite incrustar datos relacionados directamente dentro de un documento padre, lo que se conoce como desnormalización. El backend de Django MongoDB admite ambos enfoques, pero recomendamos desnormalizar los datos para un mejor rendimiento.

Para desnormalizar, elija una de las siguientes estrategias:

Utilice un modelo integrado cuando se cumplan todas las siguientes condiciones:

  • Los datos relacionados siempre se leen junto con el documento principal.

  • Los datos relacionados pertenecen a un único progenitor y no se comparten entre varios documentos.

  • El número de elementos relacionados es limitado y predecible.

Para incrustar datos relacionados, defina una clase de modelo incrustado como una subclase EmbeddedModel de, luego use un EmbeddedModelField para almacenarlo en el modelo padre.

El siguiente ejemplo define un modelo incrustado Director y luego define un modelo Movie que almacena una instancia del modelo Director:

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)

Para obtener más información sobre los modelos integrados, consulte Almacene los datos del modelo incrustado en la guía Crear modelos.

Utilice un ArrayField para almacenar una lista de valores escalares relacionados directamente en el documento principal. Los datos del array se almacenan en el mismo documento de MongoDB y se recuperan en una única operación de lectura sin realizar $lookup operaciones. Utilice esta estrategia cuando se cumplan las siguientes condiciones:

  • Los valores relacionados son escalares simples, como cadenas de caracteres o números enteros.

  • El tamaño del array es limitado y predecible.

El siguiente ejemplo define un modelo Movie que almacena una lista de cadenas en el campo 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)

Para almacenar matrices de documentos estructurados en lugar de valores escalares, utilice un EmbeddedModelArrayField. Para obtener más información, consulte la sección «Almacenar datos de matrices de modelos incrustados» en la guía «Crear modelos».

Importante

Las consultas a través de campos relacionales utilizan el operador de MongoDB,$lookup que puede ser lento para colecciones grandes. Siempre que sea posible, utilice modelos integrados. Para obtener más información sobre las consideraciones de rendimiento, consulte Limitaciones de rendimiento.

Si sus datos están estructurados de forma similar a una base de datos relacional y necesita modelar grandes conjuntos de datos jerárquicos, puede utilizar los siguientes campos relacionales de Django que vinculan documentos entre colecciones separadas:

Importante

No se pueden utilizar campos relacionales dentro de clases de modelos incrustadas o como el base_field de un ArrayField.

Utilice un campo para crear una relación de muchos a uno entre dos modelos. Cada documento del modelo que hace referencia se vincula a un documento del modelo referenciado. Pase los siguientes argumentos ForeignKey al ForeignKey() constructor:

  • to: La clase del modelo a la que enlazar

  • on_delete: El comportamiento de eliminación cuando se elimina el documento referenciado

El siguiente ejemplo vincula un modelo Comment con un modelo Movie mediante un campo ForeignKey. Al eliminar un documento sample_mflix.movies, también se eliminan todos los documentos sample_mflix.comments relacionados:

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

Para obtener más información sobre on_delete las opciones, consulte ForeignKey.on_delete en la documentación de Django.

Utilice un campo para crear una relación uno a uno entre dos modelos. Cada documento del modelo de referencia se vincula con exactamente un documento del modelo referenciado. Pase los siguientes argumentos OneToOneField al OneToOneField() constructor:

  • to: La clase del modelo a la que enlazar

  • on_delete: El comportamiento de eliminación cuando se elimina el documento referenciado

El siguiente ejemplo define un modelo EmbeddedMovie que se vincula a un modelo Movie mediante un campo OneToOneField. Al eliminar un documento sample_mflix.movies, su documento sample_mflix.embedded_movies vinculado también se elimina:

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)

Utilice un campo para crear una relación de muchos a muchos entre dos modelos. Cada documento de cualquiera de los modelos puede vincularse a varios documentos del otro modelo. Pase la clase del modelo al que se vinculará como primer argumento ManyToManyField al ManyToManyField() constructor.

El siguiente ejemplo vincula un modelo Viewer con un modelo Movie. Cada espectador puede ver varias películas, y cada película puede ser vista por varios espectadores:

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)

Si ya tienes modelos que usan campos relacionales y quieres mejorar el rendimiento de lectura, puedes convertirlos para que usen modelos incrustados. Esto elimina las operaciones $lookup y almacena todos los datos relacionados en un único documento de MongoDB.

Este ejemplo define un modelo Movie que tiene los siguientes campos relacionales:

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)

Para convertir estos campos relacionales en campos incrustados, cambie cada modelo relacionado para que extienda EmbeddedModel en lugar de models.Model, luego reemplace los campos relacionales del modelo Movie con los campos incrustados correspondientes:

  • Reemplaza el ForeignKey por un EmbeddedModelField.

  • Reemplaza el OneToOneField por un EmbeddedModelField.

  • Reemplaza el ManyToManyField por un EmbeddedModelArrayField.

El siguiente ejemplo muestra el modelo Movie convertido:

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)

Para aprender a consultar datos en modelos relacionados, consulte Consultas de campos avanzadas en la guía Especificar una consulta.

Para obtener más información sobre los campos relacionales de Django, consulte la referencia de campos del modelo en la documentación de Django.

Para obtener más información sobre los modelos integrados, consulte la sección "Almacenar datos de modelos integrados" en la guía "Crear modelos".

Volver

Modelos geoespaciales

En esta página