2012-01-13 137 views
5

這個問題適用於所有NoSQL,特別是那裏的mongoDB專家。我從一個項目設計關係數據庫開始,但客戶希望我們使用可輕鬆擴展的數據庫。爲了實現這一點,我們決定使用mongoDB。現在,我無法映射NoSQL的關係模型。我有與很多其他表的許多一對多的關係,一個用戶表如下圖所示:與NoSQL數據庫的關係

選項:

relational DB

轉換它,當MongoDB的我有幾個選項1(在用戶完成行):

users:{ 
    _id:<user_id>, 
    battles:{[battle1, battle2, ...]}, 
    items:{[item1, item2, ...]}, 
    locations:{[location1, location2, ...]}, 
    units:{[unit1, unit2, ...]}, 
} 

battles:{ 
    <battle_info> 
} 

locations:{ 
    <location_info> 
} 

units:{ 
    <units_info> 
} 

items:{ 
    <items_info> 
} 

1選項(在用戶只外鍵):

users:{ 
    _id:<user_id>, 
    battles:{[battle1_id, battle2_id, ...]}, 
    items:{[item1_id, item2_id, ...]}, 
    locations:{[location1_id, location2_id, ...]}, 
    units:{[unit1_id, unit2_id, ...]}, 
} 

battles:{ 
    <battle_info> 
} 

locations:{ 
    <location_info> 
} 

units:{ 
    <units_info> 
} 

items:{ 
    <items_info> 
} 

選項3(在其它表中的用戶ID):

users:{ 
    _id:<user_id>, 
} 

battles:{ 
    <battle_info>, 
    user:{[user1_id, user2_id, ...]} 
} 

locations:{ 
    <location_info>, 
    user:{[user1_id, user2_id, ...]} 
} 

units:{ 
    <units_info>, 
    user:{[user1_id, user2_id, ...]} 
} 

items:{ 
    <items_info>, 
    user:{[user1_id, user2_id, ...]} 
} 

選項1具有很多重複,因爲我們正在添加其他表的完整的行。我在這裏看到的一個問題是,如果某個項目或戰鬥更新了,我們將不得不在用戶表中找到它的所有事件並更新它們。但是這給我們帶來的好處是始終有一個完整的用戶對象,可以在登錄時交給客戶端應用程序。

選項2更具關係性,我們只有用戶表中其他表的mongoIds。這個選項的好處是,更新戰鬥或物品不會有太多的成本,因爲行不被複制。另一方面,當用戶登錄時,我們將不得不查找所有引用的單位,戰鬥,項目和位置以用完整的用戶對象進行響應。

選項3與選項2相反,其中users表的mongoIds保存在其他表中。這個選項對我沒有吸引力。

我真的很感激有人能指導我或想出一個更好的模型。

編輯:

基本上這是一個MMORPG遊戲,其中多個客戶端應用程序將通過Web服務連接到服務器。我們在客戶端有一個本地數據庫來存儲數據。我想要一個模型,服務器可以通過它完成一個完整的用戶對象的響應,然後更新或插入在客戶端應用上更改的數據

+0

「更好」是一個目的的問題。這些數據的訪問模式是什麼? – 2012-01-13 11:05:48

+0

基本上這是一個MMORPG遊戲,其中多個客戶端應用程序將通過web服務連接到服務器。我們在客戶端有一個本地數據庫來存儲數據。我想要一個模型,通過它服務器可以用一個完整的用戶對象進行響應,然後更新或插入在客戶端應用程序中更改的數據。 – umair 2012-01-13 11:09:12

+8

關係數據庫具有相當的擴展能力...差異應該是它們預期可以保持的數據類型,不是一個虛假的偏見,認爲RDB只適用於小數據,mongodb適用於大型 – 2012-01-13 11:09:33

回答

5

首先,NoSQL的是一刀切。在SQL中,幾乎每個1:N和M:N關係都以相同的方式建模。 NoSQL的理念是,您對數據進行建模的方式取決於數據及其使用模式。

其次,我同意馬克貝克:縮放比較難,它是通過鬆動約束來實現的。這不是一個技術問題。我喜歡和MongoDB的工作,但由於其他原因(無需對碼醜陋的SQL;不需要複雜的,臃腫的ORM等等)

現在讓我們回顧一下你的選擇: 選項1個拷貝的數據比需要的。您通常需要將的某些數據進行非規範化處理,但不會全部使用。如果是這樣,那麼獲取被引用的對象會更便宜。

選項2/3它們非常相似。這裏的關鍵是:誰在寫作?您不希望很多客戶端可以對同一個文檔進行寫入訪問,因爲這會強制您使用鎖定機制,並且/或者僅限於修改器操作。因此,選項2可能優於3.但是,如果A攻擊B,它們也會觸發寫入用戶B,因此您必須確保寫入安全。

選項4部分非規範化:您的用戶對象似乎是最重要的,所以這個怎麼樣:

user { 
battles : [ {"Name" : "The battle of foo", "Id" : 4354 }, ... ] 
... 
} 

這將使它更容易顯示例如用戶儀表板,因爲您不需要知道儀表板中的所有詳細信息。注意:數據結構然後耦合到演示文稿的細節。

選項5邊緣數據。通常情況下,相對於需要保存數據,以及:

user { 
battles : [ {"Name" : "The battle of foo", "unitsLost" : 54, "Id" : 34354 }, ... ] 
} 

這裏,unitsLost是特定於用戶和戰鬥中,因此數據坐落在圖形的邊緣。與戰鬥的名稱相反,這些數據不是非規範化的。

選項6鏈接器集合。當然,這樣的「邊緣數據」可能會變得很大,甚至可能需要單獨收集(鏈接器集合)。這完全消除了訪問鎖的問題:

user { 
    "_id" : 3443 
} 

userBattles { 
    userId : 3443, 
    battleId : 4354, 
    unitsLost : 43, 
    itemsWon : [ <some list > ], 
    // much more data 
} 

哪一個最好取決於你的應用程序的很多細節。如果用戶進行了大量的點擊(例如,您有一個細緻的界面),則可以像選擇4或6那樣分割對象。如果您確實需要一批中的所有數據,則部分非規範化不會有幫助,所以選項2將是更可取的。請記住多個寫入器問題。

+1

感謝您的詳細解答。您提出了一個有趣的觀點,並不是所有的多對多關係在NoSQL中都具有相同的結構。我想我必須根據我的需要來構造它們。 – umair 2012-01-13 13:06:16

1

選項2是要走的路。

如果您要在RDB中執行此操作,則在某個時間點(當您必須開始水平縮放時),您還需要開始刪除SQL連接並在應用程序級別連接數據。

即使10gen公司建議使用 「手動」 參考IDS:http://www.mongodb.org/display/DOCS/Database+References