MongoDB 一對多關聯性建模

來源:互聯網
上載者:User

本篇部落格翻譯自:

http://blog.mongodb.org/post/87200945828/6-rules-of-thumb-for-mongodb-schema-design-part-1?mkt_tok=3RkMMJWWfF9wsRonsq7Ldu%2FhmjTEU5z14uUsUKGxhokz2EFye%2BLIHETpodcMTcVnM7zYDBceEJhqyQJxPr3FLdcN0tJuRhTrCw%3D%3D

備忘:本譯文不是嚴格意義上的翻譯,只是在基於對該原文的理解之上,儘可能表達清楚。如有疑問或不妥,請參考原文。


很多剛從傳統SQL開發轉向MongoDB開發的朋友都會問到一個問題:如何用MongoDB表達傳統關聯式資料庫中的一對多(1 to n)關係?

基於MongoDB豐富的表達力,我們不能說我們必須採用一個標準的方法來進行1 to n的建模。稍後我們從3個具體情境來展開講解。


首先,我們將1 to n中的n進行情境細化。這個n究竟代表多大的量級呢?是幾個到幾十個?還是幾個到幾千個?還是成千上萬個?

1) 1 to n(n代表好幾個,或幾十個,反正不太多)

比如每個Person會有多個Address。此種情況下,我們採用最簡單的嵌入式文檔來建模。

{  name: 'Kate Monster',  id: '123-456-7890',  addresses : [     { street: '123 Sesame St', city: 'Anytown', cc: 'USA' },     { street: '123 Avenue Q', city: 'New York', cc: 'USA' }  ]}
這種建模的方式包含了顯而易見的優點和缺點:

優點:你不需要執行單獨的查詢就可以獲得某個Person的所有Address資訊。

缺點:你無法像操作獨立文檔那樣來操作Address資訊。你必須首先操作(比如查詢)Person文檔後,才有可能繼續操作Address。

在本執行個體中,我們不需要對Address進行獨立的操作,且Address資訊只有在關聯到某一個具體Person後才有意義。所以結論是:採用這種embedded(嵌入式)建模是非常適合Person-Address情境的。


2)1 to n(n代表好些個,比如幾十個,甚至幾百個)

比如產品(Product)和零組件(part),每個產品會有很多個零組件。這種情境下,我們可以採用引用方式來建模,如下:

零組件(Part):{    _id : ObjectID('AAAA'),    partno : '123-aff-456',    name : '#4 grommet',    qty: 94,    cost: 0.94,    price: 3.99}產品(Product):
{    name : 'left-handed smoke shifter',    manufacturer : 'Acme Corp',    catalog_number: 1234,    parts : [     // array of references to Part documents        ObjectID('AAAA'),    // reference to the #4 grommet above        ObjectID('F17C'),    // reference to a different Part        ObjectID('D2AA'),        // etc    ]}

首先每個part作為單獨的文檔存在。每個產品中包含一個數群組類型欄位(parts),這個數組中存放的是所有該產品包含的零組件的編號(_id主鍵)。當你需要根據某一個產品編號查詢該產品包含的所有組件資訊時,你可以執行以下操作:

> product = db.products.findOne({catalog_number: 1234});   // Fetch all the Parts that are linked to this Product> product_parts = db.parts.find({_id: { $in : product.parts } } ).toArray() ;
這種建模方式的優缺點也非常明顯:

優點:組件是作為獨立文檔(document)存在的,你可以對某一組件進行獨立的操作,比如查詢或更新。

缺點:如上,你必須通過兩次查詢才能找到某一個產品所屬的所有組件資訊。

在本例中,這個缺點是可以接受的,本身實現起來也不難。而且,通過這種建模,你可以輕易的將1 to n擴充到n to n,即一個產品可以包含多個組件,同時一個組件也可以被多個產品所引用(即同一組件可以被多個產品使用)。


3)1 to n(這個n代表很大的數值,比如成千上萬,甚至更大)

比如,每一個機器(host)會產生很大數量的日誌資訊(logmsg)。在這種情況下,如果你採用嵌入式建模,則一個host文檔會非常龐大,從而輕易超過MongoDB的文檔大小限制,所以不可行。如果你採用第二中方式建模,用數組來存放所有logmsg的_id值,這種方式同樣不可行,因為當日止很多時,即使單單引用objectId也會輕易超過文檔大小限制。所以此時,我們採用以下方式:

機器(hosts):{    _id : ObjectID('AAAB'),    name : 'goofy.example.com',    ipaddr : '127.66.66.66'} 日誌(logmsg):{    time : ISODate("2014-03-28T09:42:41.382Z"),    message : 'cpu is on fire!',    host: ObjectID('AAAB')       // Reference to the Host document}
我們在logsmg中,存放對host的_id引用即可。


綜上所述,在對1 to n關係建模時,我們需要考慮:

1)n代表的數量級很小,且n代表的實體不需要單獨操作時,可以採用嵌入式建模。

2)n代表的數量級比較大,或者n代表的實體需要單獨進行操作時,採用在1中用Array存放引用的方式建模。

3)n代表的數量級非常大時,我們沒有選擇,只能在n端添加一個引用到1端。


相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.