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

Come modellare un sistema di votazione Mi piace con MongoDB

Indipendentemente da come strutturi il tuo documento generale, ci sono fondamentalmente due cose di cui hai bisogno. Questa è fondamentalmente una proprietà per un "conteggio" e una "lista" di coloro che hanno già pubblicato i loro "mi piace" per assicurarsi che non ci siano duplicati inviati. Ecco una struttura di base:

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

In ogni caso, c'è un "_id" univoco per il tuo "post fotografico" e qualsiasi informazione tu voglia, ma poi gli altri campi come menzionato. La proprietà "mi piace" qui è un array e conterrà i valori "_id" univoci degli oggetti "utente" nel tuo sistema. Quindi ogni "utente" ha il proprio identificatore univoco da qualche parte, nella memoria locale o OpenId o qualcosa del genere, ma un identificatore univoco. Rimarrò con ObjectId per l'esempio.

Quando qualcuno invia un "Mi piace" a un post, vuoi emettere la seguente dichiarazione di aggiornamento:

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

Ora il $inc l'operazione aumenterà il valore di "likeCount" del numero specificato, quindi aumenta di 1. Il $push l'operazione aggiunge l'identificatore univoco per l'utente all'array nel documento per riferimento futuro.

La cosa più importante qui è tenere un registro di quegli utenti che hanno votato e cosa sta succedendo nella parte "query" della dichiarazione. Oltre a selezionare il documento da aggiornare in base al suo "_id" univoco, l'altra cosa importante è controllare che l'array "Mi piace" per assicurarsi che l'attuale utente votante non sia già presente.

Lo stesso vale per il caso inverso o per "rimuovere" il "mi piace":

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

La cosa più importante qui sono le condizioni di query utilizzate per assicurarsi che nessun documento venga toccato se tutte le condizioni non sono soddisfatte. Quindi il conteggio non aumenta se l'utente aveva già votato o diminuisce se il suo voto non era effettivamente più presente al momento dell'aggiornamento.

Ovviamente non è pratico leggere un array con un paio di centinaia di voci in un documento in qualsiasi altra parte dell'applicazione. Ma MongoDB ha anche un modo molto standard per gestire questo:

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

Questo utilizzo di $elemMatch in proiezione restituirà l'utente corrente solo se sono presenti o solo un array vuoto dove non lo sono. Ciò consente al resto della logica dell'applicazione di essere a conoscenza se l'utente corrente ha già votato o meno.

Questa è la tecnica di base e potrebbe funzionare per te così com'è, ma dovresti essere consapevole che gli array incorporati non dovrebbero essere estesi all'infinito e c'è anche un limite di 16 MB per i documenti BSON. Quindi il concetto è valido, ma non può essere utilizzato da solo se ti aspetti migliaia di "voti mi piace" sul tuo contenuto. Esiste un concetto noto come "bucketing" che viene discusso in dettaglio in questo esempio per la progettazione di schemi ibridi che consente una soluzione per archiviare un volume elevato di "Mi piace". Puoi guardarlo da usare insieme ai concetti di base qui come un modo per farlo a volume.