Relacje MongoDB: osadzenie czy odniesienie?

Jestem nowy w MongoDB -- pochodzę z relacyjnej bazy danych. Chcę zaprojektować strukturę pytań z kilkoma komentarzami, ale nie wiem, którą relację zastosować do Komentarzy: embed czy reference?

Pytanie z kilkoma komentarzami, jak stackoverflow , miałoby taką strukturę:

Question
    title = 'aaa'
    content = bbb'
    comments = ???

Na początku chcę używać osadzonych komentarzy( myślę, że {[2] } jest zalecany w MongoDB), tak:

Question
    title = 'aaa'
    content = 'bbb'
    comments = [ { content = 'xxx', createdAt = 'yyy'}, 
                 { content = 'xxx', createdAt = 'yyy'}, 
                 { content = 'xxx', createdAt = 'yyy'} ]

Jasne, ale martwię się o tym przypadku: jeśli chcę edytować podany komentarz, jak uzyskać jego treść i pytanie? nie ma _id aby pozwolić mi znaleźć jeden, ani question_ref aby pozwolić mi znaleźć jego pytanie. (Jestem tak newbie, że nie wiem, czy jest jakiś sposób, aby to zrobić bez _id i question_ref.)

Czy muszę używać ref nie embed? Następnie muszę utworzyć nową kolekcję dla komentarzy?

Author: Community, 2011-03-21

10 answers

To bardziej sztuka niż nauka. Dokumentacja Mongo na schematach jest dobrym odniesieniem, ale oto kilka rzeczy do rozważenia:

  • Włóż jak najwięcej

    Radość z bazy dokumentów polega na tym, że eliminuje wiele złączeń. Twoim pierwszym instynktem powinno być umieszczenie jak największej ilości w jednym dokumencie. Ponieważ dokumenty MongoDB mają strukturę i dlatego, że możesz efektywnie wyszukiwać w obrębie tej struktury (oznacza to, że możesz wziąć udział w dokumentu, którego potrzebujesz, więc rozmiar dokumentu nie powinien cię martwić) nie ma natychmiastowej potrzeby normalizacji danych, tak jak w SQL. W szczególności wszelkie dane, które nie są przydatne poza dokumentem nadrzędnym, powinny być częścią tego samego dokumentu.

  • Oddzielne dane, które mogą być przywoływane z wielu miejsc do własnego zbioru.

    Jest to nie tyle problem "przestrzeni dyskowej", co problem "spójności danych". Jeśli wiele rekordów będzie odnosić się do tych samych danych to jest bardziej wydajny i mniej podatny na błędy w aktualizacji pojedynczego rekordu i przechowywaniu odniesień do niego w innych miejscach.

  • Względy wielkości dokumentu

    MongoDB nakłada limit rozmiaru 4MB (16MB z 1.8) na pojedynczy dokument. W świecie GB danych brzmi to mało, ale jest to również 30 tysięcy tweetów lub 250 typowych odpowiedzi przepełnienia stosu lub 20 migoczących zdjęć. Z drugiej strony, jest to o wiele więcej informacji, niż można by chcieć przedstawić w jednym czasie na typowej stronie internetowej. Najpierw zastanów się, co ułatwi Twoje zapytania. W wielu przypadkach obawy o rozmiary dokumentów będą przedwczesne optymalizacji.

  • Złożone struktury danych:

    MongoDB może przechowywać dowolne głęboko zagnieżdżone struktury danych, ale nie może ich efektywnie przeszukiwać. Jeśli Twoje dane tworzą drzewo, las lub wykres, musisz skutecznie przechowywać każdy węzeł i jego krawędzie w osobnym dokumencie. (Zauważ, że istnieją magazyny danych specjalnie zaprojektowane dla tego typu danych, które należy rozważ również)

    Zwrócono również , ponieważ niemożliwe jest zwrócenie podzbioru elementów w dokumencie. Jeśli musisz wybrać kilka bitów każdego dokumentu, łatwiej będzie je oddzielić.

  • Spójność Danych

    MongoDB kompromituje wydajność i spójność. Regułą jest, że zmiany w pojedynczym dokumencie są zawsze atomic , podczas gdy aktualizacje wielu dokumentów nigdy nie powinny być atomic. Nie ma również możliwości "zablokowania" rekordu na serwerze (można to wbudować w logikę klienta, używając na przykład pola "Zablokuj"). Podczas projektowania schematu rozważ, w jaki sposób utrzymasz spójność danych. Ogólnie rzecz biorąc, im więcej przechowujesz w dokumencie, tym lepiej.

Za to, co opisujesz, osadzę komentarze i nadam każdemu komentarzowi pole id z ObjectID. Obiekt ma wbudowany znacznik czasu, dzięki czemu można go używać zamiast utworzonego jeśli chcesz.

 798
Author: John F. Miller,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-26 18:28:35

Ogólnie rzecz biorąc, embed jest dobry, jeśli masz relacje jeden-do-jednego lub jeden-do-wielu między podmiotami, a odniesienie jest dobre, jeśli masz relacje wiele-do-wielu.

 49
Author: ywang1724,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-13 02:19:16

Jeśli chcę edytować podany komentarz, jak uzyskać jego treść i pytanie?

Możesz odpytywać za pomocą pod-dokumentu: db.question.find({'comments.content' : 'xxx'}).

Zwróci to cały dokument z pytaniem. Aby edytować podany komentarz, musisz znaleźć komentarz na kliencie, dokonać edycji i zapisać go z powrotem do DB.

Ogólnie rzecz biorąc, jeśli dokument zawiera tablicę obiektów, okaże się, że te podrzędne obiekty będą musiały zostać zmodyfikowane po stronie klienta.

 26
Author: Gates VP,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-21 17:19:37

Cóż, jestem trochę spóźniony, ale nadal chciałbym podzielić się moim sposobem tworzenia schematu.

Mam Schematy wszystkiego, co można opisać słowem, tak jak byś to zrobił w klasycznym OOP.

E. G.

  • Skomentuj
  • konto
  • Użytkownik
  • Blogpost
  • ...

Każdy schemat można zapisać jako dokument lub Subdokument, więc deklaruję to dla każdego schematu.

Dokument:

  • może być używany jako odniesienie. (Np. użytkownik napisał komentarz - > komentarz ma odniesienie "made by" do użytkownika)
  • jest "Root" w Twojej aplikacji. (Np. blogpost - > jest strona o blogpost)

Subdocument:

  • może być użyty tylko raz / nigdy nie jest odniesieniem. (Np. komentarz jest zapisywany na blogu)
  • nigdy nie jest "Root" w Twojej aplikacji. (Komentarz po prostu pojawia się na stronie blogpost, ale strona jest nadal o blogpost)
 22
Author: Silom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-28 09:18:42

Natknąłem się na tę małą prezentację, badając to pytanie na własną rękę. Byłem zaskoczony, jak dobrze został on rozplanowany, zarówno informacje, jak i prezentacja.

Http://openmymind.net/Multiple-Collections-Versus-Embedded-Documents

Podsumowano:

Ogólnie rzecz biorąc, jeśli masz dużo [dokumentów potomnych] lub jeśli są one duże, najlepiej może być oddzielny zbiór.

Mniejsze i / lub mniej dokumentów wydają się być naturalnym dopasowaniem do / align = "left" /

 21
Author: Chris Bloom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55

Wiem, że jest to dość stare, ale jeśli szukasz odpowiedzi na pytanie OP, Jak zwrócić tylko podany komentarz, możesz użyć operatora $ (query) w następujący sposób:

db.question.update({'comments.content': 'xxx'}, {'comments.$': true})
 15
Author: finspin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-25 20:16:31

Tak, możemy użyć referencji w document.To wypełnić inny dokument tak jak sql i joins.In Mongo db oni nie mają łączy do mapowania jeden do wielu dokumentów relacji.Zamiast tego możemy użyć wypełnić aby spełnić nasz scenariusz..

var mongoose = require('mongoose')
  , Schema = mongoose.Schema

var personSchema = Schema({
  _id     : Number,
  name    : String,
  age     : Number,
  stories : [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});

var storySchema = Schema({
  _creator : { type: Number, ref: 'Person' },
  title    : String,
  fans     : [{ type: Number, ref: 'Person' }]
});

Populacja to proces automatycznego zastępowania określonych ścieżek w dokumencie dokumentami z innych kolekcji. Możemy wypełnić pojedynczy dokument, wiele dokumentów, zwykły obiekt, wiele zwykłych obiektów, lub wszystkie obiekty zwrócone z zapytania. Spójrzmy na kilka przykładów.

Lepiej możesz uzyskać więcej informacji odwiedź: http://mongoosejs.com/docs/populate.html

 14
Author: Narendran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-07 00:37:35

Właściwie to jestem dość ciekawy, dlaczego nikt nie mówił o specyfikacji UML. Zasadą jest, że jeśli masz agregację, powinieneś użyć referencji. Ale jeśli jest to kompozycja, połączenie jest silniejsze i powinieneś użyć osadzonych dokumentów.

I szybko zrozumiesz, dlaczego jest to logiczne. Jeśli obiekt może istnieć niezależnie od rodzica, wtedy będziesz chciał uzyskać do niego dostęp, nawet jeśli rodzic nie istnieje. Ponieważ po prostu nie można osadzić go w nieistniejącym rodzicu, trzeba go wprowadzić do życia w jego własnej strukturze danych. A jeśli rodzic istnieje, po prostu połącz je ze sobą, dodając ref obiektu w rodzicu.

Naprawdę nie wiesz jaka jest różnica między tymi dwoma związkami ? Oto link wyjaśniający je: agregacja a skład w UML

 14
Author: Bonjour123,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-11-05 06:53:54

Jeśli chcę edytować podany komentarz, jak uzyskać jego treść i pytanie?

Jeśli śledziłeś liczbę komentarzy i indeks komentarza, który chcesz zmienić, możesz użyć operatora kropki (przykład ).

Możesz zrobić f.ex.
db.questions.update(
    {
        "title": "aaa"       
    }, 
    { 
        "comments.0.contents": "new text"
    }
)

(jako inny sposób edycji komentarzy wewnątrz pytania)

 1
Author: serv-inc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:48

MongoDB daje swobodę bycia bez schematu i ta funkcja może powodować ból w dłuższej perspektywie, jeśli nie jest dobrze przemyślana lub zaplanowana,

Dostępne są 2 opcje: Embed lub Reference. Nie będę przerabiał definicji, ponieważ powyższe odpowiedzi dobrze je zdefiniowały.

Podczas osadzania powinieneś odpowiedzieć na jedno pytanie, Czy twój osadzony dokument będzie rosnąć, jeśli tak, to ile (pamiętaj, że jest limit 16 MB na dokument) więc jeśli masz coś w rodzaju komentarza do posta, co to jest limit liczby komentarzy, jeśli ten post stanie się wirusowy i ludzie zaczną dodawać komentarze. W takich przypadkach Referencja może być lepszym rozwiązaniem (ale nawet Referencja może rosnąć i osiągnąć limit 16 MB).

Więc jak to zrównoważyć, odpowiedź jest kombinacją różnych wzorców, sprawdź te linki i stwórz swój własny mix i dopasuj w oparciu o swoje użycie case.

Https://www.mongodb.com/blog/post/building-with-patterns-a-summary

Https://www.mongodb.com/blog/post/6-rules-of-thumb-for-mongodb-schema-design-part-1

 0
Author: r7r,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-09-02 13:50:16