MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Schema per le valutazioni degli utenti - DB chiave/valore

Prima di tutto 'Dizionario in classe utente' non è una buona idea. perché? L'aggiunta di un oggetto tariffa extra richiede il push di un nuovo elemento nell'array, il che implica che il vecchio elemento verrà rimosso e questo inserimento è il cosiddetto "spostamento di un documento ". Lo spostamento di documenti è lento e MongoDB non è così bravo a riutilizzare lo spazio vuoto, quindi spostare i documenti molto può comportare grandi quantità di file di dati vuoti (un po' di testo nel libro 'MongoDB The Definitive Guide').

Allora qual è la soluzione corretta:supponi di avere una raccolta denominata Blog e di voler implementare una soluzione di valutazione per i tuoi post del blog e inoltre tenere traccia di ogni operazione di valutazione basata sull'utente.

Lo schema per un documento del blog sarebbe come:

{
   _id : ....,
   title: ....,
   ....
   rateCount : 0,
   rateValue : 0,
   rateAverage: 0
}

Hai bisogno di un'altra raccolta (Tariffe) con questo schema di documento:

{
    _id: ....,
    userId: ....,
    postId:....,
    value: ..., //1 to 5
    date:....   
}

E devi definire un indice appropriato per esso:

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

Quando un utente vuole valutare, in primo luogo è necessario verificare se l'utente ha valutato il post o meno. supponiamo che l'utente sia 'user1' , la query sarebbe quindi

var ratedBefore = db.Rates.find({userId : 'user1', postId : 'post1'}).count()

E basato su ratedBefore , se !ratedBefore quindi inserisci un nuovo documento di valutazione nella raccolta delle tariffe e aggiorna lo stato del blog, altrimenti l'utente non è autorizzato a votare

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}});
}

Allora cosa accadrà a rateAverage ?Consiglio vivamente di calcolarlo in base a rateCount e rateValue lato client, è facile aggiornare rateAverage con mongoquery , ma non dovresti farlo. perché? La semplice risposta è:questo è un lavoro molto facile per il cliente per gestire questo tipo di lavori e mettere la media su ogni documento del blog richiede un'operazione di aggiornamento non necessaria.

la query media verrebbe calcolata come:

var blog = db.Blog.findOne({"_id" : "post1"});
var avg = blog.rateValue / blog.rateCount;
print(avg);

Con questo approccio otterrai le massime prestazioni con mongodb e avrai traccia di ogni tariffa in base a utente, post e data.