Przede wszystkim „Słownik w klasie użytkownika” nie jest dobrym pomysłem. Dlaczego? Dodanie obiektu extra rate wymaga przesłania nowego elementu do tablicy, co oznacza, że stary element zostanie usunięty, a to wstawienie jest tak zwane „przenoszenie dokumentu „.
W takim razie, jakie jest właściwe rozwiązanie:załóżmy, że masz kolekcję o nazwie Blogi i chcesz zaimplementować rozwiązanie do oceniania swoich postów na blogu, a dodatkowo śledź każdą operację oceniania opartą na użytkownikach.
Schemat dokumentu bloga wygląda następująco:
{
_id : ....,
title: ....,
....
rateCount : 0,
rateValue : 0,
rateAverage: 0
}
Potrzebujesz innej kolekcji (stawki) z tym schematem dokumentu:
{
_id: ....,
userId: ....,
postId:....,
value: ..., //1 to 5
date:....
}
I musisz zdefiniować dla niego odpowiedni indeks:
db.Rates.ensureIndex({userId : 1, postId : 1})// very useful. it will result in a much faster search operation in case you want to check if a user has rated the post previously
Gdy użytkownik chce ocenić, najpierw musisz sprawdzić, czy użytkownik ocenił post, czy nie. załóżmy, że użytkownik to 'user1'
, zapytanie będzie wyglądało następująco
var ratedBefore = db.Rates.find({userId : 'user1', postId : 'post1'}).count()
I na podstawie ratedBefore
, jeśli !ratedBefore
następnie wstaw nowy dokument oceny do zbierania cen i zaktualizuj status bloga, w przeciwnym razie użytkownik nie może oceniać
if(!ratedBefore)
{
var postId = 'post1'; // this id sould be passed before by client driver
var userId = 'user1'; // this id sould be passed before by client driver
var rateValue = 1; // to 5
var rate =
{
userId: userId,
postId: postId,
value: rateValue,
date:new Date()
};
db.Rates.insert(rate);
db.Blog.update({"_id" : postId}, {$inc : {'rateCount' : 1, 'rateValue' : rateValue}});
}
Więc co się stanie z rateAverage
?Zdecydowanie polecam obliczenie na podstawie rateCount
i rateValue
po stronie klienta łatwo jest zaktualizować rateAverage
z mongoquery
, ale nie powinieneś tego robić. Dlaczego? Prosta odpowiedź brzmi:jest to bardzo łatwe zadanie dla klienta do obsługi tego rodzaju prac i umieszczenie średniej na każdym dokumencie bloga wymaga niepotrzebnej operacji aktualizacji.
średnie zapytanie zostanie obliczone jako:
var blog = db.Blog.findOne({"_id" : "post1"});
var avg = blog.rateValue / blog.rateCount;
print(avg);
Dzięki takiemu podejściu uzyskasz maksymalną wydajność dzięki mongodb i będziesz mieć możliwość śledzenia każdej stawki w oparciu o użytkownika, post i datę.