[英]Structuring one-to-one interdocument relationship MongoDB
我剛開始使用MongoDB,但對於如何構造文檔來解決以下問題,我有些迷惑(請注意,這只是一個基本示例,與我遇到的困難相匹配)。
比方說,我有一個名為頂級文檔Family
,這些文件都存儲在一個名為收集families
和包含有關家庭,即一些基本信息
{
_id: ObjectId("foobar"),
familyName: "Simpson",
address: "743 Evergreen Terrace, SpringField",
children: [
{
_id: ObjectId("barfoo"),
firstName: "Bartholomew",
preferredName: "Bart",
middleName: "JoJo"
}
// ... etc.
]
}
現在,假設我要在應用程序中添加另一個頂級文檔: School
,存儲在名為schools
的集合中。 我需要將每個孩子與他們的學校聯系起來,每個孩子在任何時間都只能上一所學校。 在Mongo,我將如何處理? 我來自非常繁雜的RDBMS背景,在弄清楚這一點時遇到了一些困難。 我在解決方案中遇到的主要問題圍繞着以下事實:我需要有效地處理以下用例:
我采用的第一個解決方案是在我的School
文檔中創建一個enrollments
數組,該數組引用了一個孩子的_id
以及他們的全名以方便使用,即
{
_id: ObjectId("asdadssa"),
name: "Springfield Elementary",
enrollments: [
{
child_id: ObjectId("barfoo"), // Bart Simpson
fullName: "Bart Simpson" // concatenation of preferredName and familyName
}
]
}
對於第一個用例來說,這似乎很棒,它只需要顯示所有在特定學校就讀的學生。
但是,當我轉向第二個用例時,我意識到自己可能犯了一個錯誤。 您將如何算出Family
每個孩子所屬的學校? 我能看到的唯一方法是,遍歷schools
集合中的每所schools
,深入研究其enrollments
並查看child_id是否與家庭中的孩子相匹配……這似乎不是很有效嗎? 那導致了我的下一次嘗試。
因為每個孩子只能屬於一個學校,所以我認為我可以將對School
文檔的引用存儲在每個子文檔中,即Bart的文檔現在變成:
{
_id: ObjectId("barfoo"),
firstName: "Bartholomew",
preferredName: "Bart",
middleName: "JoJo",
school_id: ObjectId("asdadssa")
}
現在, 第二個用例很滿意,但第一個用例卻不滿意。
我可以看到兩個用例都滿足的唯一方法是同時使用兩個解決方案, school_id
存儲在子子文檔中,還將child_id
存儲在enrollments
數組中。
在我看來,這似乎很笨拙,這意味着您每次更改入學名額至少需要寫兩次(以便從學校退學並更換孩子)。 據我所知,MongoDB僅具有原子寫入功能,沒有事務支持,因此這看起來像是一個可能損害數據完整性的地方。
如果有任何MongoDB專家可以提出替代解決方案,那就太好了。 我知道這個特定的問題確實使人驚嘆“ RDBMS !!!!”,但這只是應用程序的一小部分,而其他一些數據確實很適合用於文檔存儲。
我現在才剛剛進入計划階段,所以我不是100%致力於Mongo,但我想我會有所作為的,因為我一直在聽到有關它的一些好消息。
對於您所描述的小用例,我會將families
收藏切換為people
或students
收藏
{
"_id" : ObjectId("barfoo"),
"family_id" : ObjectId("spamneggs"),
"name" : {
"first" : "Bartholomew",
"last" : "Simpson"
},
"school_id" : ObjectId("asdadssa")
}
將學生存儲為單獨的文檔,但將它們與通用的family_id
結合在一起(我也以另一種方式存儲名稱)。 學校無需注冊即可獲得學校信息。 我將在mongo shell中為您的兩個用例提供示例代碼。 要查找所有進入Bart學校和Bart學校文件的孩子,請執行以下操作:
> db.students.find({ "school_id" : ObjectId("asdadssa") })
> db.schools.find({ "_id" : ObjectId("asdadssa") })
要查找巴特一家的所有學校,他們的孩子都注冊了:
> var schools = []
> db.students.find({ "family_id" : ObjectId("spamneggs") }, { "_id" : 0, "school_id" : 1 }).forEach(function(doc) {
schools.push(doc.school_id)
})
> db.schools.find({ "_id" : { "$in" : schools } })
這兩個都是簡單的應用程序側連接,並且在您的情況下應該可以正常工作,因為一個家庭不會有成千上萬的孩子。 school_id
和family_id
上的索引會有所幫助。
對於寫入,僅需要使用適當的school_id
更新學生文檔。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.