2010-11-15 13 views
11

Załóżmy, że masz dużą liczbę użytkowników (M) i dużą liczbę dokumentów (N) i chcesz, aby każdy użytkownik mógł oznaczyć każdy dokument jako przeczytane lub nieprzeczytane (tak jak każdy system poczty e-mail). Jaki jest najlepszy sposób reprezentowania tego w MongoDB? Lub jakiejkolwiek innej bazy danych dokumentów?MongoDB/NOSQL: Najlepsze podejście do obsługi statusu odczytu/nieprzeczytania wiadomości

Istnieje kilka pytań na StackOverflow tym pytaniem do relacyjnych baz danych, ale nie widać żadnych zaleceń dla baz danych z dokumentu:

What's the most efficient way to remember read/unread status across multiple items?

Implementing an efficient system of "unread comments" counters

Zazwyczaj odpowiedzi obejmować listę stołowego wszystko, co użytkownik przeczytał: (tj. krotki identyfikatora użytkownika, identyfikator dokumentu) z pewnymi możliwymi optymalizacjami dla daty odcięcia pozwalającej na odczytanie całej bazy danych i ponowne uruchomienie, wiedząc, że wszystko przed tą datą jest "czytane" ".

Eksperci MongoDB/NOSQL, jakie podejścia zauważyliście w praktyce tego problemu i jak się spisali?

Odpowiedz

4
{ 
_id: messagePrefs_uniqueId, 
type: 'prefs', 
timestamp: unix_timestamp 
ownerId: receipientId, 
messageId: messageId, 
read: true/false, 
} 

{ 
_id: message_uniqueId, 
timestamp: unix_timestamp 
type: 'message', 
contents: 'this is the message', 
senderId: senderId, 
recipients: [receipientId1,receipientId2] 
} 

Powiedzmy, że masz 3 wiadomości chcesz pobrać preferencji, można je dostać za coś takiego:

db.messages.find({ 
messageId : { $in : [messageId1,messageId2,messageId3]}, 
ownerId: receipientId, 
type:'prefs' 
}) 

Jeśli wszystko czego potrzebują odczytu/nieprzeczytane można użyć tego z możliwościami upsert MongoDB za , więc nie tworzysz prefiksów dla każdej wiadomości, chyba że użytkownik ją odczytuje, to w zasadzie tworzysz obiekt prefs z własnym unikalnym id i wstawiasz go do MongoDB. Jeśli chcesz uzyskać większą elastyczność (np. Tagi powieści lub foldery), prawdopodobnie będziesz chciał utworzyć pref dla każdego odbiorcy wiadomości. Na przykład można dodać:

tags: ['inbox','tech stuff'] 

na preferencjach obiektu, a następnie uzyskać wszystkie preferencje wszystkich wiadomości oznaczone tagiem „tech rzeczy” chcesz iść coś takiego:

db.messages.find({type: 'prefs', ownerId: recipientId, tags: 'tech stuff'}) 

Mogłabyś następnie użyj messageids można znaleźć w ciągu preferencjach kwerendy i znaleźć wszystkie wiadomości, które odpowiadają:

db.messages.find((type:'message', _id: { $in : [array of messageIds from prefs]}}) 

To może być trochę trudne, jeśli chcesz zrobić coś jak liczenie, ile wiadomości każdy "tag" zawiera efektywnie. Jeśli jest to tylko garść tagów, możesz po prostu dodać .count() na końcu zapytania dla każdego zapytania. Jeśli jest to setki lub tysiące, możesz zrobić lepiej przy pomocy skryptu map/redukuj po stronie serwera lub może obiektu, który śledzi liczbę wiadomości na znacznik na użytkownika.

+1

Dziękuję, więc twoja rekomendacja jest zasadniczo tym samym rodzajem tabeli "krotki/dołącz", jak w przypadku relacji, prawda? Jakiś szczególny powód, dla którego przechowujesz zarówno wiadomości, jak i prefiksy w tej samej kolekcji? –

+0

Rzeczą w MongoDB jest to, że zazwyczaj bardziej płaski obiekt można uczynić lepszym. Chociaż może przechowywać struktury zagnieżdżone, nie jest najlepszym rozwiązaniem w przypadku zapytań lub dostania się do nich później, aby je zmienić. Tak więc wiele rzeczy może wyglądać podobnie do relacji, ale z mniejszą ilością abstrakcji z powodu nie używania tabel. Tak naprawdę nie ma powodu, dla którego przechowywałbym je w tej samej kolekcji, poza tym, że nie lubię mieć bazillionowych kolekcji. Jeśli planujesz posiadanie milionów wiadomości, rozsądne może być korzystanie z różnych kolekcji, dzięki czemu możesz skonfigurować indeksy, aby lepiej pasowały do ​​każdego obiektu. – Klinky

3

Jeśli przechowujesz tylko proste wartości boolowskie, takie jak read/unread, inną metodą jest osadzenie tablicy w każdym dokumencie, który zawiera listę użytkowników, którzy ją przeczytali.

{ 
    _id: 'document#42', 
    ... 
    read_by: ['user#83', 'user#2702'] 
} 

Następnie powinno być w stanie indeksować tej dziedzinie, co do szybkich zapytań dla dokumentów czytanych po Użytkownikiem a users-who-odczytu dokumentu.

db.documents.find({read_by: 'user#83'}) 

db.documents.find({_id: 'document#42}, {read_by: 1}) 

Jednak uważam, że ja zwykle zapytań do wszystkich dokumentów, które mają nie zostały przeczytane przez konkretnego użytkownika, a nie mogę wymyślić żadnego rozwiązania, które mogą skorzystać z indeksu w tym walizka.Podejrzewam, że nie jest możliwe zrobienie tego szybko, bez posiadania obu tablic, tak aby każdy użytkownik był uwzględniony w każdym dokumencie (lub w tabeli dołączania), ale miałby duży koszt przechowywania.

+0

Odnośnie ostatniego punktu dotyczącego odpytywania * nieprzeczytanych * wiadomości, ale z użyciem pola * read_by *, popraw mnie, jeśli się mylę, ale nie można tego osiągnąć za pomocą klauzuli ** $ not **, jak w '$ not: {$ in: [{id: 'user # 83'}]} '? – bigp

Powiązane problemy