簡體   English   中英

構建一對一的文檔間關系MongoDB

[英]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收藏切換為peoplestudents收藏

{
    "_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_idfamily_id上的索引會有所幫助。

對於寫入,僅需要使用適當的school_id更新學生文檔。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM