sql >> Database >  >> NoSQL >> MongoDB

Schema voor gebruikersbeoordelingen - Key/Value DB

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.



  1. Sorteer subvelden met onbekende ouder

  2. MongoDB-configuratie met node.js:Fout:kan geen verbinding maken met [localhost:27017]

  3. Kan de MongoDB WiredTiger-engine worden gebruikt voor vooraf geaggregeerde rapporten? (vergelijkbaar met MMAPv1)

  4. Wat is sneller:`find().limit(1)` of `findOne()` in MongoDB/Mongoose?