Het maakt niet uit hoe u uw algemene document structureert, er zijn in principe twee dingen die u nodig hebt. Dat is in feite een eigenschap voor een "telling" en een "lijst" van degenen die hun "vind ik leuk" al hebben gepost om ervoor te zorgen dat er geen duplicaten worden ingediend. Hier is een basisstructuur:
{
"_id": ObjectId("54bb201aa3a0f26f885be2a3")
"photo": "imagename.png",
"likeCount": 0
"likes": []
}
Hoe dan ook, er is een unieke "_id" voor uw "fotopost" en welke informatie u maar wilt, maar dan de andere velden zoals vermeld. De "likes"-eigenschap hier is een array en die zal de unieke "_id" -waarden van de "user" -objecten in uw systeem bevatten. Dus elke "gebruiker" heeft ergens zijn eigen unieke identifier, ofwel in lokale opslag of OpenId of zoiets, maar een unieke identifier. Ik blijf bij ObjectId
voor het voorbeeld.
Als iemand een bericht 'vind ik leuk' plaatst, wil je de volgende update-verklaring uitgeven:
db.photos.update(
{
"_id": ObjectId("54bb201aa3a0f26f885be2a3"),
"likes": { "$ne": ObjectId("54bb2244a3a0f26f885be2a4") }
},
{
"$inc": { "likeCount": 1 },
"$push": { "likes": ObjectId("54bb2244a3a0f26f885be2a4") }
}
)
Nu de $inc
bewerking daar zal de waarde van "likeCount" verhogen met het opgegeven getal, dus verhoog het met 1. De $push
bewerking voegt de unieke identificatie voor de gebruiker toe aan de array in het document voor toekomstig gebruik.
Het belangrijkste hier is om bij te houden welke gebruikers hebben gestemd en wat er gebeurt in het "query"-gedeelte van de verklaring. Afgezien van het selecteren van het document dat moet worden bijgewerkt met zijn eigen unieke "_id", is het andere belangrijke om die "vind-ik-leuks"-array te controleren om er zeker van te zijn dat de huidige stemgebruiker daar niet al in zit.
Hetzelfde geldt voor het omgekeerde geval of het "verwijderen" van de "like":
db.photos.update(
{
"_id": ObjectId("54bb201aa3a0f26f885be2a3"),
"likes": ObjectId("54bb2244a3a0f26f885be2a4")
},
{
"$inc": { "likeCount": -1 },
"$pull": { "likes": ObjectId("54bb2244a3a0f26f885be2a4") }
}
)
Het belangrijkste hier is dat de queryvoorwaarden worden gebruikt om ervoor te zorgen dat er geen document wordt aangeraakt als niet aan alle voorwaarden wordt voldaan. De telling neemt dus niet toe als de gebruiker al had gestemd of neemt af als zijn/haar stem op het moment van de update niet meer aanwezig was.
Het is natuurlijk niet praktisch om een array met een paar honderd vermeldingen in een document terug te lezen in een ander deel van uw toepassing. Maar MongoDB heeft ook een heel standaard manier om daarmee om te gaan:
db.photos.find(
{
"_id": ObjectId("54bb201aa3a0f26f885be2a3"),
},
{
"photo": 1
"likeCount": 1,
"likes": {
"$elemMatch": { "$eq": ObjectId("54bb2244a3a0f26f885be2a4") }
}
}
)
Dit gebruik van $elemMatch
in projectie zal alleen de huidige gebruiker retourneren als deze aanwezig is of alleen een lege array waar ze niet zijn. Hierdoor kan de rest van uw applicatielogica weten of de huidige gebruiker al een stem heeft uitgebracht of niet.
Dat is de basistechniek en kan voor u werken zoals het is, maar u moet zich ervan bewust zijn dat embedded arrays niet oneindig moeten worden uitgebreid, en er is ook een harde limiet van 16 MB voor BSON-documenten. Het concept is dus goed, maar kan niet op zichzelf worden gebruikt als je duizenden "like-stemmen" op je inhoud verwacht. Er is een concept dat bekend staat als "bucketing" dat in dit voorbeeld in detail wordt besproken voor hybride schema-ontwerp dat één oplossing mogelijk maakt om een groot aantal "likes" op te slaan. Je kunt dat bekijken om samen met de basisconcepten hier te gebruiken als een manier om dit op volume te doen.