1. ReferenceField
- 功能:用於在一個文件中引用另一個文件,類似於關係型資料庫中的外來鍵。
- 儲存方式:儲存被引用文件的 ObjectId。
- 查詢行為:當訪問該欄位時,直接載入被引用的目標文件。
- 適用場景:適合用於多對一關係或文件之間有獨立管理需求的情況。
特點:
- 引用的目標文件儲存在單獨的集合中。
- 目標文件獨立存在,可以被其他文件引用。
- 訪問引用欄位時會觸發資料庫查詢,從而獲取目標文件的資料。
示例:
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 中。
- 查詢行為:父文件查詢時,巢狀文件的資料會隨父文件一起返回。
- 適用場景:適用於一對一或一對多關係,且巢狀文件與父文件緊密相關,不需要獨立查詢。
特點:
- 巢狀文件的資料是父文件的一部分,查詢父文件時自動返回巢狀資料。
- 巢狀文件不能被其他文件引用。
- 文件大小可能變大,適合子文件較小的場景。
示例:
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。
- 查詢行為:當訪問該欄位時,延遲載入目標文件資料。
- 適用場景:適合需要引用其他文件,但在大部分情況下不訪問引用文件的場景,最佳化效能。
特點:
- 引用目標文件的方式與
ReferenceField
相同,但支援延遲載入。 - 訪問引用欄位時會觸發查詢;如果不訪問,則不會載入目標文件資料。
- 提升效能,減少資料庫查詢次數。
示例:
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 |
查詢行為 | 查詢時直接載入目標文件 | 查詢父文件時直接返回巢狀資料 | 延遲載入目標文件,只有在訪問時才查詢目標文件 |
效能 | 查詢時需要額外載入目標文件 | 查詢時目標文件資料已包含在父文件中 | 查詢時不會載入目標文件,訪問時才觸發查詢 |
適用關係 | 一對一、多對一 | 一對一、一對多 | 一對一、多對一 |
資料耦合性 | 父文件和目標文件獨立,松耦合 | 父文件和巢狀文件緊密耦合 | 父文件和目標文件獨立,松耦合 |
文件大小 | 文件大小較小,引用目標文件資料 | 文件大小可能較大,巢狀文件資料增加父文件大小 | 文件大小較小,引用目標文件資料 |
適用場景 | - 目標文件需要獨立管理 - 資料訪問較頻繁 | - 父文件與子文件總是一起操作 - 資料巢狀結構較小 | - 延遲訪問目標文件 - 最佳化效能,減少查詢次數 |
推薦使用場景
- ReferenceField:
- 目標文件獨立且可能被多次引用。
- 資料需要在多個地方管理,不適合巢狀儲存的場景。
- 例如:使用者(
User
)和文章(Article
)之間的關係。
- EmbeddedDocumentField:
- 父文件與子文件緊密關聯,通常一起使用。
- 資料結構較小且耦合緊密,適合一對一、一對多的巢狀儲存。
- 例如:使用者(
User
)和地址(Address
)的關係。
- LazyReferenceField:
- 引用文件資料較大,訪問不頻繁,適合延遲載入。
- 需要減少資料庫查詢時的效能最佳化場景。
- 例如:訂單(
Order
)引用的使用者(User
)資訊,但訂單查詢中不常用使用者詳情。