Pytanie wiele do wielu relacji z nosql (mongodb i mangusta)


Jestem w związku z wieloma osobami z mongoDb i mongoose.js, wiem, że jest wiele opcji, moja sytuacja jest następująca:

Mam dwa dokumenty, użytkownika i projekty, jeden użytkownik może mieć wiele projektów, a jeden projekt może mieć wielu użytkowników, więc w moim przypadku mam 4 opcje:

1 - Tablica id_user wewnątrz dokumentu projektu.

2 - Tablica dokumentu id_project wewnątrz dokumentu użytkownika.

3 - Tablica id_user wewnątrz dokumentu projektu && Tablica   id_project wewnątrz dokumentu użytkownika.

4 - Trzeci schemat mapowania użytkownika i relacji projektu (np   relacyjna baza danych).

Opcje 1 i 2 są niedostępne, ponieważ, wyobrażając sobie w scenariuszu opcji 1, gdybym chciał znaleźć wszystkie projekty od użytkownika, będę musiał szukać tego identyfikatora użytkownika w każdej tablicy dokumentów projektowych użytkowników (przemierzam tę tablicę w każdym projekcie) zdecydowanie nie jest to dobre podejście.

Opcja 3 jest dobra, ale będę musiał przeprowadzić transakcję, aby upewnić się, że oba dokumenty zostaną zapisane, nie jest tak źle, ponieważ oba dokumenty będą dużo bardziej czytelne niż napisane

Opcja 4 jest prostsza, ponieważ kiedy dodaję jednego użytkownika do projektu, wystarczy dodać nowy dokument z dwoma identyfikatorami (to dobre rozwiązanie, myślę, ponieważ nie będę musiał przejmować się transakcją, to jest dobre rozwiązanie?)

Jakie jest najlepsze rozwiązanie?


11
2017-08-03 03:36


pochodzenie




Odpowiedzi:


Wręcz przeciwnie, rozwiązanie 1 i 2 jest najlepszym rozwiązaniem. Rozwiązanie 3 można rozważyć, gdy częstotliwość aktualizacji / tworzenia jest znacznie mniejsza w porównaniu z częstotliwością odczytu projektów i użytkowników, mimo że aktualizacja / tworzenie wymaga dwóch pytań, co ułatwi czytanie.

Aby wybrać rozwiązanie 1 i 2, należy wziąć pod uwagę częstotliwość odczytu. Czy będziesz potrzebował częściej projektów użytkownika lub zastosowań projektu i wybierzesz według tego. Jeśli uważasz, że obie są względnie tej samej częstotliwości, lepiej zachować obiekt użytkownika jako mniej klastrowany, jak to możliwe. Bez względu na wybraną opcję, rozważ zachowanie index w tablicy przechowującej _ids (projektów lub użytkowników).

Na przykład

userSchema = new Schema(
            {//otherstuff
               project_ids: [{type: Schema.Types.ObjectId, ref: 'Project'}})
              ...
            }) 
userSchema.index({'project_ids':1})

lub

projectSchema = new Schema(
            {//otherstuff
               user_ids: [{type: Schema.Types.ObjectId, ref: 'User'}})
              ...
            }) 
projectSchema.index({'user_ids':1})

Prowadzenie indeksu w tablicy _id znacznie poprawi szybkość twoich zapytań po stronie, w której obawiasz się znacznych kosztów ogólnych.

Ale trzymaj index tylko wtedy, gdy ta relacja jest istotną relacją z wieloma zapytaniami. Jeśli jest to tylko dodatkowa cecha twojego projektu, możesz to zrobić without też indeks.

Jeśli użytkownik może robić wiele rzeczy i ma wiele relacji, będzie wymagał tego obiektu użytkownika w całej aplikacji, więc jeśli aplikacja nie jest specyficzna dla danego projektu, lepiej nie umieszczać identyfikatorów projektu w schemacie użytkownika . Ale skoro po prostu umieszczamy numery identyfikacyjne, to i tak nie ma to większego znaczenia. Nie musisz się o to martwić.

Indeks Reg na obu tablicach: Tak, możesz oczywiście. Ale kiedy idziesz na rozwiązanie 3, nie potrzebujesz wcale indeksu, ponieważ nie będziesz robić zapytania, aby uzyskać listę projektów użytkownika lub listy użytkowników w projekcie. Rozwiązanie 3 sprawia, że ​​czytanie jest bardzo łatwe, ale nieco uciążliwe. Ale jak wspomniałeś, że dotyczy to twojego przypadku użycia reading>>writing, idź z rozwiązaniem 3, ale zawsze istnieje niebezpieczeństwo niespójności danych, którymi musisz się zająć.

Indeksowanie sprawia, że ​​rzeczy stają się szybsze. Iść przez doktorzy i zrobić trochę googlowania. Nic fajnego. Zapytanie o indeksowane tablice jest wydajniejsze niż normalne tablice. Na przykład Załóżmy, że korzystasz z rozwiązania 2. Zapisz identyfikatory projektu w polu project_ids.

Możesz łatwo uzyskać dostęp do projektów użytkownika. To jest proste.

Ale aby uzyskać użytkowników projektu1. Potrzebujesz takiego zapytania.

User.find({project_ids:project._id},function(err,docs){
     //here docs will be the list of the users of project1
})
//The above query might be slow if the user base is large. 
//But it can be improved vastly by indexing the project_ids field in the User schema.

Podobne rozwiązanie 1. Każdy projekt ma pole user_ids. Załóżmy, że mamy użytkownika 1. Aby uzyskać projekty użytkownika, wykonujemy następujące zapytanie

Project.find({user_ids:user1._id},function(err,docs){
      //here docs will be the projects of user1
      //But it can be improved vastly by indexing the user_ids field in the Project schema.

Jeśli zastanawiasz się nad rozwiązaniem 1 w stosunku do rozwiązania 2, rozwiązanie 1 jest lepsze, jak sądzę. Mogą być przypadki, w których potrzebujesz użytkownika bez jego projektów, ale szanse na wymaganie projektu bez użytkowników są dość niskie. Ale to zależy od twojego konkretnego przypadku użycia.


7
2017-08-03 09:36



"lepiej jest trzymać obiekt użytkownika jako mniej klastrowany, jak to możliwe" Co masz na myśli mówiąc o tym? Czy mogę używać tego indeksu w obu schematach (projektach i użytkownikach)? - Rodrigo Fonseca
a rozwiązanie 1 i 2 nie jest dobre, ponieważ oba sposoby będą czytane niemal w tej samej ilości, ale będą napisane z mniejszą częstotliwością - Rodrigo Fonseca
@RodrigoFonseca sprawdź edycję. - ma08
Indeksowanie w zasadzie porządkuje dokumenty tak, że kwerenda na indeksowanym polu jest superszybka. Wartość 1 wskazuje rosnący indeks, możesz mieć indeks opadający, używając -1. Tu naprawdę nie ma znaczenia, ale zawiera liczby i daty. Dokładnie. Sprawdź pułapki transakcji (scenariusz awarii, np. Niekonsekwencji) i oceń swoje opcje. - ma08
@RodrigoFonseca sprawdź edycję. - ma08


Cóż, rozwiązanie 1 i 2 nie wygląda tak źle! Jeśli indeksujesz tablicę obiektów, możesz wtedy uzyskać bezpośredni dostęp do tego, co chcesz.

Rozwiązanie 3 również wygląda dobrze, ale 4, nie bardzo, potrzebujesz więcej zapytań, z wyjątkiem sytuacji, gdy masz dużo zmian między relacjami między projektami a użytkownikami, ale nie samymi.

Preferuję rozwiązanie 1 z indeksem na tablicy. Sądzę, że wiele razy, gdy potrzebujesz obiektu projektu, zależy od użytkownika lub bezpośrednio przez id, więc .find() zrobi wszystko, co chcesz. Myślę, że nie jest źle, aby zachować schemat użytkownika z minimalnymi informacjami, wyglądają jak obiekty izolujące i możesz potrzebować ich do innych celów.


2
2017-08-03 07:11



OK, rozwiązanie jest dobre, ale jeśli chcę znaleźć wszystkie projekty od odpowiedniego użytkownika? Będę musiał przejść przez obiekt ID tablicy użytkownika we wszystkich dokumentach projektu? To nie jest dobre rozwiązanie, myślę, i czy możesz dać mi krótkie wyjaśnienie na temat działania tego indeksu? - Rodrigo Fonseca
Spojrzeć na to. Wszystko, czego potrzebujesz, aby zdobyć tych użytkowników .find({user_ids:YOURID}) i aby być pewnym, że jest tak szybki, uruchom go w powłoce Mongo w ten sposób: db.collection.find({user_ids:YOURID}).explain() i zobacz, jak długo to trwa. - Foad Nosrati Habibi
Indeksy Multikey? użyję tego: połączyć co za różnica? - Rodrigo Fonseca
Indeksy Multikey to rodzaj indeksowania używanego w tablicach. Mongoose wykryje sam rodzaj indeksowania. Więc nie martw się o to. Wszystko, co zrobiłeś, jest w porządku. - Foad Nosrati Habibi