Uanset hvordan du strukturerer dit overordnede dokument, er der grundlæggende to ting, du har brug for. Det er dybest set en egenskab for en "optælling" og en "liste" over dem, der allerede har skrevet deres "synes godt om" for at sikre, at der ikke er indsendt dubletter. Her er en grundlæggende struktur:
{
"_id": ObjectId("54bb201aa3a0f26f885be2a3")
"photo": "imagename.png",
"likeCount": 0
"likes": []
}
Hvorom alting er, så er der et unikt "_id" til dit "fotopost" og hvilken information du ønsker, men så de andre felter som nævnt. Egenskaben "likes" her er et array, og det kommer til at indeholde de unikke "_id" værdier fra "user" objekterne i dit system. Så hver "bruger" har deres egen unikke identifikator et eller andet sted, enten i lokal lagring eller OpenId eller noget, men en unik identifikator. Jeg holder mig til ObjectId
for eksempel.
Når nogen sender et "synes godt om" til et opslag, vil du udsende følgende opdateringserklæring:
db.photos.update(
{
"_id": ObjectId("54bb201aa3a0f26f885be2a3"),
"likes": { "$ne": ObjectId("54bb2244a3a0f26f885be2a4") }
},
{
"$inc": { "likeCount": 1 },
"$push": { "likes": ObjectId("54bb2244a3a0f26f885be2a4") }
}
)
Nu $inc
operation der vil øge værdien af "likeCount" med det angivne tal, så øg med 1. $push
operation tilføjer den unikke identifikator for brugeren til arrayet i dokumentet til fremtidig reference.
Det vigtigste her er at føre en fortegnelse over de brugere, der har stemt, og hvad der sker i "forespørgslen"-delen af erklæringen. Bortset fra at vælge dokumentet, der skal opdateres med dets eget unikke "_id", er den anden vigtige ting at kontrollere, at "synes godt om"-array for at sikre, at den nuværende stemmebruger ikke allerede er derinde.
Det samme gælder for det omvendte tilfælde eller "fjernelse" af "like":
db.photos.update(
{
"_id": ObjectId("54bb201aa3a0f26f885be2a3"),
"likes": ObjectId("54bb2244a3a0f26f885be2a4")
},
{
"$inc": { "likeCount": -1 },
"$pull": { "likes": ObjectId("54bb2244a3a0f26f885be2a4") }
}
)
Det vigtigste her er forespørgselsbetingelserne, der bruges til at sikre, at intet dokument bliver rørt, hvis alle betingelser ikke er opfyldt. Så antallet stiger ikke, hvis brugeren allerede havde stemt, eller falder, hvis deres stemme faktisk ikke var til stede længere på tidspunktet for opdateringen.
Det er selvfølgelig ikke praktisk at læse et array med et par hundrede poster i et dokument tilbage i en hvilken som helst anden del af din ansøgning. Men MongoDB har også en meget standard måde at håndtere det på:
db.photos.find(
{
"_id": ObjectId("54bb201aa3a0f26f885be2a3"),
},
{
"photo": 1
"likeCount": 1,
"likes": {
"$elemMatch": { "$eq": ObjectId("54bb2244a3a0f26f885be2a4") }
}
}
)
Denne brug af $elemMatch
i projektion vil kun returnere den aktuelle bruger, hvis de er til stede eller blot et tomt array, hvor de ikke er. Dette gør det muligt for resten af din applikationslogik at være opmærksom på, om den aktuelle bruger allerede har afgivet en stemme eller ej.
Det er den grundlæggende teknik og kan fungere for dig, som den er, men du skal være opmærksom på, at indlejrede arrays ikke bør udvides uendeligt, og der er også en hård 16MB-grænse på BSON-dokumenter. Så konceptet er sundt, men kan bare ikke bruges alene, hvis du forventer 1000-vis af "like-stemmer" på dit indhold. Der er et koncept kendt som "bucketing", som diskuteres i detaljer i dette eksempel for Hybrid Schema-design, der tillader én løsning til at gemme en stor mængde "likes". Du kan se på det for at bruge sammen med de grundlæggende begreber her som en måde at gøre dette på volumen.