MongoDB
 sql >> Baza danych >  >> NoSQL >> MongoDB

Planowanie i zarządzanie schematami w MongoDB (nawet jeśli nie jest to schemat)

Kiedy wprowadzono MongoDB, główną wyróżnioną cechą była zdolność do bycia „bez schematu”. Co to znaczy? Oznacza to, że w tej samej kolekcji można przechowywać dokumenty JSON, każdy o innej strukturze. To jest całkiem niezłe. Ale problem zaczyna się, gdy trzeba odzyskać dokumenty. Jak stwierdzić, że pobrany dokument ma określoną strukturę lub czy zawiera określone pole, czy nie? Musisz przejrzeć wszystkie dokumenty i wyszukać to konkretne pole. Dlatego warto dokładnie zaplanować schemat MongoDB, zwłaszcza w przypadku dużych aplikacji.

Jeśli chodzi o MongoDB, nie ma konkretnego sposobu na zaprojektowanie schematu. Wszystko zależy od Twojej aplikacji i tego, jak Twoja aplikacja będzie wykorzystywać dane. Istnieje jednak kilka typowych praktyk, które można zastosować podczas projektowania schematu bazy danych. Tutaj omówię te praktyki oraz ich zalety i wady.

Modelowanie jeden-do-kilku (osadzanie)

Ten projekt jest bardzo dobrym przykładem osadzania dokumentów. Rozważ ten przykład kolekcji Person, aby zilustrować to modelowanie.

{
  name: "Amy Cooper",
  hometown: "Seoul",
  addresses: [
    { city: 'New York', state: 'NY', cc: 'USA' },
    { city: 'Jersey City', state: 'NJ', cc: 'USA' }
  ]
}

Plusy:

  • Możesz uzyskać wszystkie informacje w jednym zapytaniu.

Minusy:

  • Osadzone dane są całkowicie zależne od dokumentu nadrzędnego. Nie możesz przeszukiwać osadzonych danych niezależnie.
  • Rozważmy przykład, w którym tworzysz system śledzenia zadań przy użyciu tego podejścia. Następnie umieścisz wszystkie zadania specyficzne dla jednej osoby w kolekcji Person. Jeśli chcesz uruchomić zapytanie typu:Pokaż mi wszystkie zadania, których terminem jest jutro. Może to być bardzo trudne, nawet jeśli jest to proste zapytanie. W takim przypadku powinieneś rozważyć inne podejścia.

Modelowanie jeden-do-wielu (odniesienia)

W tego typu modelowaniu dokument nadrzędny będzie zawierał identyfikator referencyjny (ID obiektu) dokumentów podrzędnych. Aby pobrać dokumenty, musisz użyć łączeń na poziomie aplikacji (łączenia dwóch dokumentów po pobraniu ich z bazy danych na poziomie aplikacji), więc nie ma łączeń na poziomie bazy danych. W związku z tym obciążenie bazy danych zostanie zmniejszone. Rozważ ten przykład:

// 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')
  ]
}

Załóżmy, że z każdym produktem może być powiązanych kilka tysięcy części. W przypadku tego rodzaju bazy danych odwoływanie się jest idealnym rodzajem modelowania. W dokumencie produktu umieszczasz identyfikatory wszystkich powiązanych części. Następnie możesz użyć złączeń na poziomie aplikacji, aby uzyskać części dla konkretnego produktu.

Plusy:

  • W tego typu modelowaniu każda część jest osobnym dokumentem, dzięki czemu można zastosować wszystkie zapytania dotyczące części w tych dokumentach. Nie musisz być zależny od dokumentu nadrzędnego.
  • Bardzo łatwe do wykonania operacje CRUD (Tworzenie, Odczytywanie, Aktualizowanie, Zapisywanie) niezależnie na każdym dokumencie.

Minusy:

  • Jedną z głównych wad tej metody jest konieczność wykonania jednego dodatkowego zapytania w celu uzyskania szczegółów części. Aby można było wykonać połączenia na poziomie aplikacji z dokumentem produktu, aby uzyskać niezbędny zestaw wyników. Może to więc prowadzić do spadku wydajności bazy danych.
Kilkadziesiąt — Zostań administratorem baz danych MongoDB — wprowadzenie MongoDB do produkcjiDowiedz się, co trzeba wiedzieć, aby wdrażać, monitorować, zarządzać i skalować MongoDB. Pobierz za darmo

Modelowanie od jednego do miliona (odniesienia do rodziców)

Kiedy musisz przechowywać mnóstwo danych w każdym dokumencie, nie możesz użyć żadnego z powyższych podejść, ponieważ MongoDB ma ograniczenie rozmiaru do 16 MB na dokument. Doskonałym przykładem tego rodzaju scenariusza może być system rejestrowania zdarzeń, który zbiera logi z różnych typów maszyn i przechowuje je w kolekcjach Logs i Machine.

Tutaj nie możesz nawet myśleć o korzystaniu z metody osadzania, która przechowuje wszystkie informacje z dzienników dla konkretnego komputera w jednym dokumencie. Dzieje się tak, ponieważ za kilka godzin rozmiar dokumentu przekroczy 16 MB. Nawet jeśli przechowujesz tylko identyfikatory referencyjne wszystkich dokumentów z dziennikami, nadal wyczerpiesz limit 16 MB, ponieważ niektóre maszyny mogą generować miliony komunikatów dzienników w ciągu jednego dnia.

Tak więc w tym przypadku możemy użyć metody odwoływania się do rodzica. W tym podejściu, zamiast przechowywać identyfikatory referencyjne dokumentów podrzędnych w dokumencie nadrzędnym, będziemy przechowywać identyfikatory referencyjne dokumentów nadrzędnych we wszystkich dokumentach podrzędnych. W naszym przykładzie będziemy przechowywać identyfikator ObjectID maszyny w dokumentach dzienników. Rozważ ten przykład:

// 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
}

Załóżmy, że chcesz znaleźć ostatnie 3000 dzienników maszyny 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()

Odwołania dwukierunkowe

W tym podejściu przechowujemy referencje po obu stronach, co oznacza, że ​​referencja rodzica będzie przechowywana w dokumencie podrzędnym, a referencja dziecka będzie przechowywana w dokumencie nadrzędnym. To sprawia, że ​​wyszukiwanie jest stosunkowo łatwe w modelowaniu od jednego do wielu. Na przykład możemy wyszukiwać zarówno w dokumentach nadrzędnych, jak i zadaniach. Z drugiej strony takie podejście wymaga dwóch oddzielnych zapytań, aby zaktualizować jeden dokument.

// 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
}

Wniosek

Ostatecznie wszystko zależy od wymagań aplikacji. Możesz zaprojektować schemat MongoDB w sposób, który jest najkorzystniejszy dla Twojej aplikacji i zapewnia wysoką wydajność. Oto kilka podsumowanych kwestii, które możesz wziąć pod uwagę podczas projektowania schematu.

  1. Zaprojektuj schemat w oparciu o wzorce dostępu do danych Twojej aplikacji.
  2. Nie ma potrzeby każdorazowego umieszczania dokumentów. Połącz dokumenty tylko wtedy, gdy zamierzasz używać ich razem.
  3. Rozważ duplikację danych, ponieważ przechowywanie jest obecnie tańsze niż moc obliczeniowa.
  4. Zoptymalizuj schemat pod kątem częstszych przypadków użycia.
  5. Tablice nie powinny wyrastać poza granice. Jeśli jest więcej niż kilkaset dokumentów podrzędnych, nie umieszczaj ich.
  6. Preferuj sprzężenia na poziomie aplikacji niż na poziomie bazy danych. Dzięki odpowiedniemu indeksowaniu i właściwemu wykorzystaniu pól projekcji możesz zaoszczędzić dużo czasu.

  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Scal dwa pola tablicy w mongoDB

  2. Jak uzyskać konkretny osadzony dokument w kolekcji MongoDB?

  3. Osadzona populacja mangusty

  4. Zapytanie agregujące MongoDB przy użyciu sterownika PHP

  5. Przypadki użycia updateOne nad findOneAndUpdate w MongoDB