2017-03-10 103 views
0

我一直在研究MongoDB,並遇到了一個特別有趣的模式來存儲文檔之間的關係。這種模式涉及包含ID數組引用子文檔如下父文檔:MongoDB和Mongoose:文檔引用ID的嵌套數組

//Parent Schema 
export interface Post extends mongoose.Document { 
    content: string; 
    dateCreated: string; 
    comments: Comment[]; 
} 

let postSchema = new mongoose.Schema({ 
    content: { 
    type: String, 
    required: true 
    }, 
    dateCreated: { 
    type: String, 
    required: true 
    }, 
    comments: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Comment' }] //nested array of child reference ids 
}); 

那孩子被引用:

//Child Schema 
export interface Comment extends mongoose.Document { 
    content: string; 
    dateCreated: string; 
} 

let commentSchema = new mongoose.Schema({ 
    content: { 
    type: String, 
    required: true 
    }, 
    dateCreated: { 
    type: String, 
    required: true 
    } 
}); 

這一點,直到我去送一切似乎很好,很正常來自前端的請求創建一條新評論。該請求必須包含Post _id(更新帖子)和新評論,這兩個都是使用普通關係數據庫時發送的請求的共同點。在將新評論寫入數據庫時​​出現問題。而不是像一個正常的關係數據庫那樣寫一個數據庫,我必須做2次寫入和1次讀取。第一次寫入插入新評論並檢索_id。然後讀取以檢索帖子_id與請求一起發送,以便我可以將新的Comment _id推送到嵌套參考數組。最後,最後一次寫入將Post更新回數據庫。

這看起來效率極低。我的問題是雙重的:

  1. 是否有處理這種關係的模式(包含子引用一組ID父母)更好/更有效的方式?

  2. 如果不是,使用這種模式的好處是什麼,而不是A)將父_id存儲在類似於傳統外鍵的子屬性上,或者B)利用MongoDB文檔並存儲評論數組,而不是評論的參考ID數組。

在此先感謝您的洞察!

+0

而不是引用註釋作爲列表中的郵件只是使用一個引用在對帖子的評論中。你需要它的帖子ID,只寫一次。關於與一個職位相關的所有評論的撤回。 – Myonara

+0

@Myonara,感謝您的反饋,我很感激。然而,我的問題更具體地是一個架構問題,爲什麼會選擇這種模式而不是你提到的模式,以及是否有更好的方法來實現所討論的第一種模式。 –

+0

下面是一個CMS風格的用例https://docs.mongodb.com/ecosystem/use-cases/storing-comments/。這談到選項B.希望它可以幫助你清除一些東西。 – Veeram

回答

1

關於你提到的第一個問題:

您明確要求一個更好的方式與存儲在父子的IDS工作。我敢肯定,如果它必須是這種模式,沒有更好的方法來處理這個問題。

但是這個問題在關係數據庫中也存在。如果您想將自己的帖子保存在關係數據庫中(使用該模式),則還必須先創建註釋,獲取其ID,然後更新帖子。當然,您可以在一個請求中發送所有這些任務,這可能比使用貓鼬更有效,但是需要完成的工作類型是相同的。

關於你提到的第二個問題:

在變式A的好處是,你可以,例如得到這個職位,並立即知道有多少意見了,不問MongoDB的經過大概的文件hundrets。

在B變種的好處是,你可以存儲更多引用到一個文檔中的註釋(單篇文章),比整個意見,因爲mongos 16MB文件大小的限制。


然而,你所提到的一個缺點是,維持這種結構效率不高。我認爲,這只是一個展示這種情況的例子,所以這裏是我會做的: 我會根據具體情況決定使用什麼。

  • 如果該文件將被讀了很多,並沒有太大的寫入,這是不可能比16MB增長較大:嵌入子文檔。通過這種方式,您可以在單個查詢中獲取所有數據。

  • 如果您需要從多個引用文檔等文件真正的數據必須是一致的,那麼你別無選擇,只能引用它。

  • 如果您需要從多個引用文檔其他文件數據consitency不是超級重要從第一bulletpoint限制應用,然後嵌入子文檔,並編寫代碼保持數據的一致性。

  • 如果您需要從多個其他文件引用文檔,都寫了很多,但不是閱讀的時候,你可能會更好過引用他們,因爲這是比較容易的代碼,因爲您不需要編寫代碼來同步重複數據。

在這種特殊情況下(後/評論)從孩子引用父(讓孩子知道父母_id)可能是一個好主意,因爲它更容易維護比周圍的其他方法,以及如果直接嵌入,文檔可能會增長到16MB以上。如果我肯定知道文檔不會超過16MB,嵌入它們將會更好,因爲它更快地查詢數據。

+0

感謝您的詳細分析。我很感激! –