首页 > 其他分享 >ReferenceField、EmbeddedDocumentField和LazyReferenceField的使用和总结对比

ReferenceField、EmbeddedDocumentField和LazyReferenceField的使用和总结对比

时间:2024-11-18 16:08:35浏览次数:1  
标签:目标 EmbeddedDocumentField 嵌套 查询 LazyReferenceField 文档 引用 ReferenceField 加载

1. ReferenceField

  • 功能:用于在一个文档中引用另一个文档,类似于关系型数据库中的外键。
  • 存储方式:存储被引用文档的 ObjectId
  • 查询行为:当访问该字段时,直接加载被引用的目标文档。
  • 适用场景:适合用于多对一关系或文档之间有独立管理需求的情况。

特点

  1. 引用的目标文档保存在单独的集合中。
  2. 目标文档独立存在,可以被其他文档引用。
  3. 访问引用字段时会触发数据库查询,从而获取目标文档的数据。

示例

from mongoengine import Document, StringField, ReferenceField

class Author(Document):
    name = StringField()

class Book(Document):
    title = StringField()
    author = ReferenceField(Author)  # 引用 Author 文档

使用:

# 创建引用关系
author = Author(name="John Doe").save()
book = Book(title="My Book", author=author).save()

# 获取数据
print(book.author.name)  # 访问时查询 Author 集合,输出 "John Doe"

2. EmbeddedDocumentField

  • 功能:用于在文档中嵌套另一个文档,直接将嵌套文档作为字段存储在父文档中。
  • 存储方式:嵌套文档数据直接存储在父文档的 BSON 中。
  • 查询行为:父文档查询时,嵌套文档的数据会随父文档一起返回。
  • 适用场景:适用于一对一或一对多关系,且嵌套文档与父文档紧密相关,不需要独立查询。

特点

  1. 嵌套文档的数据是父文档的一部分,查询父文档时自动返回嵌套数据。
  2. 嵌套文档不能被其他文档引用。
  3. 文档大小可能变大,适合子文档较小的场景。

示例

from mongoengine import Document, StringField, EmbeddedDocument, EmbeddedDocumentField

class Address(EmbeddedDocument):
    city = StringField()
    street = StringField()

class User(Document):
    name = StringField()
    address = EmbeddedDocumentField(Address)  # 嵌套 Address 文档

使用:

# 嵌套文档数据存储
address = Address(city="New York", street="5th Avenue")
user = User(name="Alice", address=address).save()

# 获取数据
print(user.address.city)  # 输出 "New York"

3. LazyReferenceField

  • 功能:与 ReferenceField 类似,但支持延迟加载,被引用的目标文档只有在访问时才会触发查询。
  • 存储方式:存储被引用文档的 ObjectId
  • 查询行为:当访问该字段时,延迟加载目标文档数据。
  • 适用场景:适合需要引用其他文档,但在大部分情况下不访问引用文档的场景,优化性能。

特点

  1. 引用目标文档的方式与 ReferenceField 相同,但支持延迟加载。
  2. 访问引用字段时会触发查询;如果不访问,则不会加载目标文档数据。
  3. 提升性能,减少数据库查询次数。

示例

from mongoengine import Document, StringField, LazyReferenceField

class Author(Document):
    name = StringField()

class Book(Document):
    title = StringField()
    author = LazyReferenceField(Author)  # 延迟加载 Author 文档

使用:

# 创建引用关系
author = Author(name="Jane Doe").save()
book = Book(title="Another Book", author=author).save()

# 延迟加载目标文档
print(book.author.fetch().name)  # fetch() 查询 Author 文档,输出 "Jane Doe"

三者比较总结

特性 ReferenceField EmbeddedDocumentField LazyReferenceField
存储方式 存储目标文档的 ObjectId 直接存储嵌套文档的数据 存储目标文档的 ObjectId
查询行为 查询时直接加载目标文档 查询父文档时直接返回嵌套数据 延迟加载目标文档,只有在访问时才查询目标文档
性能 查询时需要额外加载目标文档 查询时目标文档数据已包含在父文档中 查询时不会加载目标文档,访问时才触发查询
适用关系 一对一、多对一 一对一、一对多 一对一、多对一
数据耦合性 父文档和目标文档独立,松耦合 父文档和嵌套文档紧密耦合 父文档和目标文档独立,松耦合
文档大小 文档大小较小,引用目标文档数据 文档大小可能较大,嵌套文档数据增加父文档大小 文档大小较小,引用目标文档数据
适用场景 - 目标文档需要独立管理 - 数据访问较频繁 - 父文档与子文档总是一起操作 - 数据嵌套结构较小 - 延迟访问目标文档 - 优化性能,减少查询次数

推荐使用场景

  1. ReferenceField
    • 目标文档独立且可能被多次引用。
    • 数据需要在多个地方管理,不适合嵌套存储的场景。
    • 例如:用户(User)和文章(Article)之间的关系。
  2. EmbeddedDocumentField
    • 父文档与子文档紧密关联,通常一起使用。
    • 数据结构较小且耦合紧密,适合一对一、一对多的嵌套存储。
    • 例如:用户(User)和地址(Address)的关系。
  3. LazyReferenceField
    • 引用文档数据较大,访问不频繁,适合延迟加载。
    • 需要减少数据库查询时的性能优化场景。
    • 例如:订单(Order)引用的用户(User)信息,但订单查询中不常用用户详情。

标签:目标,EmbeddedDocumentField,嵌套,查询,LazyReferenceField,文档,引用,ReferenceField,加载
From: https://www.cnblogs.com/pmna/p/18552898

相关文章