Když byl představen MongoDB, hlavní zdůrazněnou vlastností byla jeho schopnost „bez schématu“. Co to znamená? To znamená, že je možné ukládat dokumenty JSON, každý s jinou strukturou, ve stejné kolekci. To je docela fajn. Problém ale začíná, když potřebujete získat dokumenty. Jak poznáte, že načtený dokument má určitou strukturu nebo zda obsahuje určité pole či nikoli? Musíte procházet všechny dokumenty a hledat to konkrétní pole. To je důvod, proč je užitečné pečlivě naplánovat schéma MongoDB, zejména pro velké aplikace.
Pokud jde o MongoDB, neexistuje žádný konkrétní způsob, jak navrhnout schéma. Vše závisí na vaší aplikaci a na tom, jak bude vaše aplikace data využívat. Existují však některé běžné postupy, které můžete při navrhování schématu databáze dodržovat. Zde budu diskutovat o těchto praktikách a jejich výhodách a nevýhodách.
Osobní modelování (vkládání)
Tento design je velmi dobrým příkladem vkládání dokumentů. Pro ilustraci tohoto modelování zvažte tento příklad kolekce osob.
{
name: "Amy Cooper",
hometown: "Seoul",
addresses: [
{ city: 'New York', state: 'NY', cc: 'USA' },
{ city: 'Jersey City', state: 'NJ', cc: 'USA' }
]
}
Výhody:
- Všechny informace můžete získat v jediném dotazu.
Nevýhody:
- Vložená data jsou zcela závislá na nadřazeném dokumentu. Vložená data nelze prohledávat nezávisle.
- Podívejte se na příklad, kde pomocí tohoto přístupu vytváříte systém sledování úkolů. Poté do kolekce Osoba vložíte všechny úkoly specifické pro jednu osobu. Pokud chcete vypálit dotaz jako:Ukaž mi všechny úkoly, které mají zítra jako termín. To může být velmi obtížné, i když se jedná o jednoduchý dotaz. V tomto případě byste měli zvážit jiné přístupy.
Modelování typu One-to-Many (odkazování)
V tomto typu modelování bude nadřazený dokument obsahovat referenční ID (ObjectID) podřízených dokumentů. K načtení dokumentů musíte použít spojení na úrovni aplikace (sloučení dvou dokumentů po jejich načtení z DB na úrovni aplikace), takže se nespojí žádná databázová úroveň. Tím se sníží zatížení databáze. Zvažte tento příklad:
// Parts collection
{
_id: ObjectID(1234),
partno: '1',
name: ‘Intel 100 Ghz CPU',
qty: 100,
cost: 1000,
price: 1050
}
// Products collection
{
name: 'Computer WQ-1020',
manufacturer: 'ABC Company',
catalog_number: 1234,
parts: [
ObjectID(‘1234’), <- Ref. for Part No: 1
ObjectID('2345'),
ObjectID('3456')
]
}
Předpokládejme, že každý produkt může mít několik tisíc součástí. Pro tento druh databáze je odkazování ideálním typem modelování. Referenční ID všech přidružených dílů vložíte pod produktový dokument. Poté můžete použít spojení na úrovni aplikace k získání dílů pro konkrétní produkt.
Výhody:
- V tomto typu modelování je každá součást samostatným dokumentem, takže na tyto dokumenty můžete použít všechny dotazy související se součástmi. Není třeba být závislý na nadřazeném dokumentu.
- Velmi snadné provádět operace CRUD (vytváření, čtení, aktualizace, zápis) na každém dokumentu nezávisle.
Nevýhody:
- Jednou z hlavních nevýhod této metody je, že pro získání podrobností o součásti musíte provést jeden dotaz navíc. Abyste mohli provést spojení na úrovni aplikace s dokumentem produktu, abyste získali potřebnou sadu výsledků. Takže to může vést k poklesu výkonu DB.
Modelování od jednoho k milionu (odkazování na rodiče)
Když potřebujete v každém dokumentu uložit spoustu dat, nemůžete použít žádný z výše uvedených přístupů, protože MongoDB má omezení velikosti 16 MB na dokument. Dokonalým příkladem tohoto druhu scénáře může být systém protokolování událostí, který shromažďuje protokoly z různých typů strojů a ukládá je do sbírek protokolů a strojů.
Zde nemůžete ani pomyslet na použití přístupu Embedding, který ukládá všechny informace o protokolech pro konkrétní stroj do jednoho dokumentu. Je to proto, že během několika hodin bude velikost dokumentu větší než 16 MB. I když ukládáte pouze referenční ID všech dokumentů protokolů, stále vyčerpáte limit 16 MB, protože některé počítače mohou generovat miliony zpráv protokolů za jediný den.
V tomto případě tedy můžeme použít rodičovský přístup. V tomto přístupu namísto ukládání referenčních ID podřízených dokumentů v nadřazeném dokumentu uložíme referenční ID nadřazeného dokumentu do všech podřízených dokumentů. V našem příkladu tedy uložíme ObjectID stroje do dokumentů protokolů. Zvažte tento příklad:
// Machines collection
{
_id : ObjectID('AAA'),
name : 'mydb.example.com',
ipaddr : '127.66.0.4'
}
// Logs collection
{
time : ISODate("2015-09-02T09:10:09.032Z"),
message : 'WARNING: CPU usage is critical!',
host: ObjectID('AAA') -> references Machine document
}
Předpokládejme, že chcete najít posledních 3000 protokolů počítače 127.66.0.4:
machine = db.machines.findOne({ipaddr : '127.66.0.4'});
msgs = db.logmsg.find({machine: machine._id}).sort({time : -1}).limit(3000).toArray()
Dvoucestné odkazování
V tomto přístupu ukládáme reference na obě strany, což znamená, že rodičovská reference bude uložena v podřízeném dokumentu a podřízená reference bude uložena v nadřazeném dokumentu. Díky tomu je vyhledávání v jednom až mnoha modelování relativně snadné. Můžeme například vyhledávat v nadřazených i úkolových dokumentech. Na druhou stranu tento přístup vyžaduje dva samostatné dotazy k aktualizaci jednoho dokumentu.
// person
{
_id: ObjectID("AAAA"),
name: "Bear",
tasks [
ObjectID("AAAD"),
ObjectID("ABCD"), -> Reference of child document
ObjectID("AAAB")
]
}
// tasks
{
_id: ObjectID("ABCD"),
description: "Read a Novel",
due_date: ISODate("2015-11-01"),
owner: ObjectID("AAAA") -> Reference of parent document
}
Závěr
Nakonec vše závisí na požadavcích vaší aplikace. Schéma MongoDB můžete navrhnout způsobem, který je pro vaši aplikaci nejpřínosnější a poskytuje vám vysoký výkon. Zde je několik souhrnných úvah, které můžete vzít v úvahu při navrhování schématu.
- Navrhněte schéma na základě vzorů přístupu k datům vaší aplikace.
- Není nutné vkládat dokumenty pokaždé. Kombinujte dokumenty, pouze pokud je budete používat společně.
- Zvažte duplikaci dat, protože úložiště je v dnešní době levnější než výpočetní výkon.
- Optimalizujte schéma pro častější případy použití.
- Pole by neměla vyrůstat z hranice. Pokud existuje více než několik stovek podřízených dokumentů, nevkládejte je.
- Upřednostňujte spojení na úrovni aplikace před spojeními na úrovni databáze. Při správném indexování a správném používání promítacích polí vám to může ušetřit spoustu času.