2015-01-18 38 views
9

Obecnie pracuję nad aplikacją mobilną. Zasadniczo ludzie mogą publikować swoje zdjęcia, a obserwatorzy mogą polubić takie zdjęcia jak Instagram. Używam mongodb jako bazy danych. Podobnie jak na Instagramie, może być wiele polubień dla pojedynczych zdjęć. Zatem używanie dokumentu dla pojedynczego "jak" z indeksem wydaje się nieuzasadnione, ponieważ zmarnuje dużo pamięci. Chciałbym jednak, aby użytkownik dodał coś szybko. Moje pytanie brzmi: jak modelować "podobne"? Zasadniczo model danych jest bardzo podobny do instagram, ale za pomocą Mongodb.Jak modelować system głosowania "lubi" z MongoDB

+0

Możesz mieć pole "polubienia" dla każdego dokumentu wskazuje na zdjęcie. i użyj operatora '$ inc', aby zaktualizować pole dla dokumentu w sposób atomowy. Ale jeśli mógłbyś opublikować swoją aktualną strukturę dokumentu i ponownie sformułować swoje wymagania prawidłowo, otrzymasz dobre odpowiedzi. – BatScream

+2

Dodawanie podróbek będzie wyjątkowo łatwe i szybkie, możesz przekazać wszystkie potrzebne dane bezpośrednio do serwera i dosłownie zrobić jedno zapytanie, aby wstawić je bezpośrednio do DB. Będziesz jednak chciał buforować i agregować podobne liczby, ponieważ policzenie tych polubień będzie nieprzyjemne. Większość witryn, w tym instagram, używa licznika, np. @BatScream mówi, że za pomocą $ inc (lub cokolwiek istnieje w technologii, której używają) do buforowania podobnego istnienia, dzięki czemu łatwo jest powiedzieć, ile osób lubi coś ma – Sammaye

Odpowiedz

23

Bez względu na to, jak układasz cały dokument, potrzebujesz dwóch rzeczy. Jest to w zasadzie właściwość cztery "liczba" i "lista" tych, którzy już napisali tam "jak" w celu zapewnienia, że ​​nie ma żadnych duplikatów złożone. Oto podstawowa struktura:

{ 
    "_id": ObjectId("54bb201aa3a0f26f885be2a3") 
    "photo": "imagename.png", 
    "likeCount": 0 
    "likes": [] 
} 

W każdym razie, nie jest unikalny „_id” do „foto post” i bez względu na informacje, które chcesz, a potem pozostałe pola jak wspomniano. Właściwość "likes" jest tutaj tablicą, która będzie przechowywała niepowtarzalne wartości "_id" z obiektów "user" w twoim systemie. Więc każdy "użytkownik" ma gdzieś swój unikalny identyfikator, albo w pamięci lokalnej, albo w OpenID, albo coś w tym rodzaju, ale niepowtarzalny identyfikator. Przykleję się do przykładu za pomocą ObjectId.

Gdy ktoś złoży „podobny” do postu, chcesz wydać następujące oświadczenie aktualizacji:

db.photos.update(
    { 
     "_id": ObjectId("54bb201aa3a0f26f885be2a3"), 
     "likes": { "$ne": ObjectId("54bb2244a3a0f26f885be2a4") } 
    }, 
    { 
     "$inc": { "likeCount": 1 }, 
     "$push": { "likes": ObjectId("54bb2244a3a0f26f885be2a4") } 
    } 
) 

Teraz operacja $inc nie zwiększy wartość „likeCount” o liczbie określonej, więc zwiększyć o 1. Operacja $push dodaje unikalny identyfikator użytkownika do tablicy w dokumencie, aby można ją było wykorzystać w przyszłości.

Najważniejszą rzeczą tutaj jest prowadzenie rejestru tych użytkowników, którzy głosowali i co dzieje się w części "zapytanie". Oprócz wyboru dokumentu do aktualizacji przez jego własny unikatowy "_id", inne ważne jest sprawdzenie, czy tablica "lubi", aby upewnić się, że bieżący użytkownik głosowania już tam nie jest.

To samo jest prawdą dla odwrotnym przypadku, albo „usuwanie” the „jak”:

db.photos.update(
    { 
     "_id": ObjectId("54bb201aa3a0f26f885be2a3"), 
     "likes": ObjectId("54bb2244a3a0f26f885be2a4") 
    }, 
    { 
     "$inc": { "likeCount": -1 }, 
     "$pull": { "likes": ObjectId("54bb2244a3a0f26f885be2a4") } 
    } 
) 

Głównym ważne jest tutaj to warunki zapytań używany, aby upewnić się, że żaden dokument nie jest dotykany, jeśli wszystkie warunki nie są spełnione. Tak więc liczba nie wzrasta, jeśli użytkownik już głosował lub zmniejszał, jeśli ich głos nie był już obecny w czasie aktualizacji.

Oczywiście nie jest praktyczne czytanie tablicy zawierającej kilkaset wpisów w dokumencie w dowolnej innej części aplikacji. Ale MongoDB ma bardzo standardowy sposób obsługi, który także:

db.photos.find(
    { 
     "_id": ObjectId("54bb201aa3a0f26f885be2a3"), 
    }, 
    { 
     "photo": 1 
     "likeCount": 1, 
     "likes": { 
      "$elemMatch": { "$eq": ObjectId("54bb2244a3a0f26f885be2a4") } 
     } 
    } 
) 

Ta użycie $elemMatch w projekcji zwróci jedynie bieżącego użytkownika, jeśli są one obecne, czy tylko pusta tablica, gdzie nie są. Dzięki temu reszta logiki aplikacji może być świadoma, czy bieżący użytkownik już oddał głos, czy nie.

To jest podstawowa technika i może działać tak, jak jest, ale powinieneś wiedzieć, że wbudowane tablice nie powinny być nieskończenie rozszerzone, a istnieje również twardy limit 16 MB na dokumentach BSON. Koncepcja jest więc dobra, ale nie można jej używać samodzielnie, jeśli spodziewasz się tysięcy "podobnych głosów" w swoich materiałach.Istnieje pojęcie znane jako "bucketing", które jest omówione szczegółowo w tym przykładzie dla Hybrid Schema design, które pozwala jednemu rozwiązaniu na przechowywanie dużej ilości "polubień". Możesz na to spojrzeć i używać podstawowych pojęć tutaj jako sposobu na zrobienie tego przy woluminie.

+1

Dobra odpowiedź, przepraszam za przyniesienie to, ale jaki jest twój pomysł na wdrożenie takiego rozwiązania (zamiast używania sub dokumentu do utrzymywania polubień lub głosów) http://stackoverflow.com/questions/26914380/schema-for-user-ratings-key-value-db – Disposer

+0

@Disposer Ogólną zasadą jest uczynienie tego tak prostym, jak to możliwe, aby sprawdzić, czy ktoś głosował lub nie, i odczytać całkowitą liczbę głosów bez agregacji lub przynajmniej podzielić na jak najmniej dokumentów. Inne modele opierają się na agregacji w czasie rzeczywistym lub w inny sposób nie są atomowe w aktualizacjach. Szybki do napisania i szybki do odczytania. W przypadku przedmiotów o wysokiej aktywności zazwyczaj jest to, czego potrzebujesz. –

+0

@Neil Lunn. Dzięki za odpowiedź. W rzeczywistości moja struktura danych jest bardzo podobna do twojej i planuję użyć projektu z wyszywaniem. Zastanawiam się, jak dobry jest wynik wyszukiwania wielu wiader z polubień za pomocą operatora $ elemMatch. Powiedzmy, że jest 300000 polubień zdjęcia, mam 300 wiaderek, a każdy z nich zawiera 1000 polubień. Czy sprawnie wiadomo, czy obecny użytkownik już oddał głos, czy nie? Interesuje mnie również "Inne modele polegają na agregacji w czasie rzeczywistym", o której wspomniałeś, czy możesz wyjaśnić więcej, aby móc ocenić więcej opcji? – user2914635