Pierwszą rzeczą, którą należy zrozumieć o populacji mangusty, jest to, że nie jest to magia, ale po prostu wygodna metoda, która pozwala na odzyskanie powiązanych informacji bez robienia tego samemu.
Koncepcja ta jest zasadniczo do użytku, gdy zdecydujesz, że będziesz musiał umieścić dane w oddzielnym zbiorze, a nie osadzać tych danych, a główne rozważania powinny dotyczyć zazwyczaj rozmiaru dokumentu lub gdy powiązane informacje podlegają częstym aktualizacjom, które mogłyby spowodować utrzymywanie osadzonych danych nieporęcznych.
Część „nie magiczna” polega na tym, że zasadniczo to, co dzieje się pod okładkami, polega na tym, że kiedy „odwołujesz się” do innego źródła, funkcja populate tworzy dodatkowe zapytanie/zapytania do tej „powiązanej” kolekcji, aby „scalić” te wyniki rodzica obiekt, który pobrałeś. Możesz to zrobić sam, ale metoda jest dla wygody, aby uprościć zadanie. Oczywistym aspektem „wydajności” jest to, że nie ma ani jednej podróży w obie strony do bazy danych (instancja MongoDB) w celu pobrania wszystkich informacji. Zawsze jest więcej niż jeden.
Jako próbkę weź dwie kolekcje:
{
"_id": ObjectId("5392fea00ff066b7d533a765"),
"customerName": "Bill",
"items": [
ObjectId("5392fee10ff066b7d533a766"),
ObjectId("5392fefe0ff066b7d533a767")
]
}
A przedmioty:
{ "_id": ObjectId("5392fee10ff066b7d533a766"), "prod": "ABC", "qty": 1 }
{ "_id": ObjectId("5392fefe0ff066b7d533a767"), "prod": "XYZ", "qty": 2 }
„Najlepsze”, co można zrobić za pomocą modelu „odnośnego” lub użycia funkcji wypełniania (pod maską), to:
var order = db.orders.findOne({ "_id": ObjectId("5392fea00ff066b7d533a765") });
order.items = db.items.find({ "_id": { "$in": order.items } ).toArray();
Tak więc są wyraźnie „przynajmniej” dwa zapytania i operacje, aby „dołączyć” te dane.
Koncepcja osadzania jest zasadniczo odpowiedzią MongoDB na to, jak radzić sobie z nieobsługiwaniem „połączeń”. Więc zamiast dzielić dane na znormalizowane kolekcje, spróbuj osadzić „powiązane” dane bezpośrednio w dokumencie, który ich używa. Zaletą tego rozwiązania jest to, że istnieje pojedyncza operacja „odczytu” do pobierania „powiązanych” informacji, a także pojedynczy punkt operacji „zapisu” do aktualizacji zarówno wpisów „rodzicowych”, jak i „podrzędnych”, chociaż często nie można do nich pisać „wiele” dzieci naraz bez przetwarzania „list” na kliencie lub w inny sposób akceptowania „wielu” operacji zapisu, najlepiej w przetwarzaniu „wsadowym”.
Dane wyglądają wtedy raczej tak (w porównaniu do powyższego przykładu):
{
"_id": ObjectId("5392fea00ff066b7d533a765"),
"customerName": "Bill",
"items": [
{ "_id": ObjectId("5392fee10ff066b7d533a766"), "prod": "ABC", "qty": 1 },
{ "_id": ObjectId("5392fefe0ff066b7d533a767"), "prod": "XYZ", "qty": 2 }
]
}
Dlatego faktyczne pobranie danych to tylko kwestia:
db.orders.findOne({ "_id": ObjectId("5392fea00ff066b7d533a765") });
Plusy i minusy każdego z nich zawsze będą w dużej mierze zależeć od sposobu użytkowania aplikacji. Ale w skrócie:
Osadzanie
-
Całkowity rozmiar dokumentu z osadzonymi danymi zwykle nie przekracza 16 MB pamięci (limit BSON) lub w inny sposób (jako wskazówka) mają tablice zawierające 500 lub więcej wpisów.
-
Dane osadzone na ogół nie wymagają częstych zmian. Możesz więc żyć z „duplikacją”, która pochodzi z denormalizacji, która nie powoduje konieczności aktualizowania tych „duplikatów” tymi samymi informacjami w wielu dokumentach nadrzędnych tylko po to, aby wywołać zmianę.
-
Powiązane dane są często używane w połączeniu z rodzicem. Oznacza to, że jeśli twoje przypadki „odczytu/zapisu” prawie zawsze wymagają „odczytu/zapisu” zarówno do rodzica, jak i dziecka, to sensowne jest osadzenie danych dla operacji atomowych.
Odniesienia
-
Powiązane dane zawsze będą przekraczać limit 16 MB BSON. Zawsze można rozważyć hybrydowe podejście „bucketing”, ale nie można przekroczyć ogólnego sztywnego limitu głównego dokumentu. Typowe przypadki to „post” i „komentarz”, w przypadku których oczekuje się, że aktywność „komentarzy” będzie bardzo duża.
-
Powiązane dane wymagają regularnej aktualizacji. Lub zasadniczo przypadek, w którym „normalizujesz”, ponieważ te dane są „udostępniane” wielu rodzicom, a „powiązane” dane są zmieniane na tyle często, że niepraktyczne byłoby aktualizowanie osadzonych elementów w każdym „rodzicu”, w którym występuje ten „podrzędny” element . Łatwiejszym przypadkiem jest po prostu odwołanie się do „dziecka” i jednorazowe wprowadzenie zmiany.
-
Istnieje wyraźne oddzielenie odczytów i zapisów. W przypadku, gdy być może nie będziesz zawsze wymagać tych „powiązanych” informacji podczas czytania „rodzica” lub w inny sposób nie musisz zawsze zmieniać „rodzica” podczas pisania do dziecka, może być dobry powód, aby oddzielić model jak wskazano. Dodatkowo, jeśli istnieje ogólna chęć aktualizacji wielu „dokumentów podrzędnych” na raz, w których te „dokumenty podrzędne” są w rzeczywistości odniesieniami do innego zbioru, to często implementacja jest bardziej efektywna, gdy dane znajdują się w oddzielnym zbiorze. kolekcja.
Tak więc w rzeczywistości istnieje znacznie szersza dyskusja na temat „za/przeciw” dla obu pozycji w dokumentacji MongoDB na temat modelowania danych, która obejmuje różne przypadki użycia i sposoby podejścia za pomocą modelu osadzania lub modelu referencyjnego, co jest obsługiwane przez metodę populate.
Mamy nadzieję, że „kropki” są przydatne, ale ogólnie zaleca się rozważenie wzorców wykorzystania danych w aplikacji i wybranie tego, co jest najlepsze. Posiadanie „opcji” osadzenia „powinno” być powodem, dla którego wybrałeś MongoDB, ale w rzeczywistości to sposób, w jaki Twoja aplikacja „wykorzystuje dane”, będzie podejmował decyzję, która metoda pasuje do której części modelowania danych (ponieważ nie jest „wszystko albo nic”) najlepszy.
- Zauważ, że odkąd to zostało napisane, MongoDB wprowadził
$lookup
operator, który rzeczywiście wykonuje „połączenia” między kolekcjami na serwerze. Na potrzeby ogólnej dyskusji w tym miejscu, w większości przypadków „lepiej” niż narzut „wielu zapytań” poniesiony przezpopulate()
i ogólnie „wiele zapytań” nadal istnieje „znaczne obciążenie” poniesione z dowolnym$lookup
operacja.
Podstawowa zasada projektowania brzmi:„osadzone” oznacza „już tam”, w przeciwieństwie do „pobierania z innego miejsca”. Zasadniczo różnica między „w kieszeni” a „na półce”, a w terminologii I/O zwykle bardziej jak „na półce w bibliotece w centrum” , a zwłaszcza dalej w przypadku żądań sieciowych.