Allereerst is 'Woordenboek in gebruikersklasse' geen goed idee. waarom? Het toevoegen van een object met extra snelheid vereist het pushen van een nieuw item naar de array, wat inhoudt dat het oude item wordt verwijderd, en deze invoeging wordt zo genoemd "een document verplaatsen ". Het verplaatsen van documenten is traag en MongoDB is niet zo goed in het hergebruiken van lege ruimte, dus het veel verplaatsen van documenten kan resulteren in grote hoeveelheden lege gegevensbestanden (sommige tekst in het 'MongoDB The Definitive Guide'-boek).
Wat is dan de juiste oplossing:neem aan dat u een verzameling met de naam Blogs hebt en u wilt een beoordelingsoplossing voor uw blogberichten implementeren, en houd bovendien elke gebruikersgebaseerde tariefbewerking bij.
Het schema voor een blogdocument ziet er als volgt uit:
{
_id : ....,
title: ....,
....
rateCount : 0,
rateValue : 0,
rateAverage: 0
}
U heeft een andere collectie (Tarieven) nodig met dit documentschema:
{
_id: ....,
userId: ....,
postId:....,
value: ..., //1 to 5
date:....
}
En je moet er een goede index voor definiëren:
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
Wanneer een gebruiker een beoordeling wil geven, moet u eerst controleren of de gebruiker de post heeft beoordeeld of niet. neem aan dat de gebruiker 'user1'
. is , de vraag zou dan zijn
var ratedBefore = db.Rates.find({userId : 'user1', postId : 'post1'}).count()
En gebaseerd op ratedBefore
, als !ratedBefore
voeg vervolgens een nieuw tariefdocument toe aan de Tarievenverzameling en update de blogstatus, anders mag de gebruiker niet beoordelen
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}});
}
Wat gaat er dan gebeuren met rateAverage
?Ik raad ten zeerste aan om het te berekenen op basis van rateCount
en rateValue
aan de clientzijde is het eenvoudig om rateAverage
bij te werken met mongoquery
, maar je moet het niet doen. waarom? Het simpele antwoord is:dit is een zeer gemakkelijke taak voor de klant om dit soort werken aan te pakken en het gemiddelde van elk blogdocument vereist een onnodige update-operatie.
de gemiddelde zoekopdracht zou als volgt worden berekend:
var blog = db.Blog.findOne({"_id" : "post1"});
var avg = blog.rateValue / blog.rateCount;
print(avg);
Met deze aanpak krijgt u maximale prestaties met mongodb en houdt u elk tarief bij op basis van gebruiker, bericht en datum.