sql >> Databasteknik >  >> NoSQL >> MongoDB

Hur man modellerar ett likes-röstningssystem med MongoDB

Oavsett hur du strukturerar ditt övergripande dokument finns det i princip två saker du behöver. Det är i grunden en egenskap för en "räkning" och en "lista" över de som redan har lagt upp sina "gilla" för att säkerställa att inga dubbletter skickas in. Här är en grundläggande struktur:

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

Hur det än är så finns det ett unikt "_id" för ditt "fotoinlägg" och vilken information du vill, men sedan de andra fälten som nämnts. Egenskapen "likes" här är en array, och som kommer att hålla de unika "_id"-värdena från "user"-objekten i ditt system. Så varje "användare" har sin egen unika identifierare någonstans, antingen i lokal lagring eller OpenId eller något, men en unik identifierare. Jag håller mig till ObjectId för exemplet.

När någon skickar ett "gilla" till ett inlägg vill du utfärda följande uppdateringsmeddelande:

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

Nu är $inc operation där kommer att öka värdet på "likeCount" med det angivna antalet, så öka med 1. $push operation lägger till den unika identifieraren för användaren till arrayen i dokumentet för framtida referens.

Det viktigaste här är att hålla ett register över de användare som röstade och vad som händer i "fråga"-delen av uttalandet. Förutom att välja dokumentet som ska uppdateras med sitt eget unika "_id", är den andra viktiga saken att kontrollera att "gilla"-arrayen för att se till att den aktuella röstanvändaren inte redan finns där.

Detsamma gäller för omvänd fallet eller "ta bort" "gilla":

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

Det viktigaste här är att frågevillkoren används för att säkerställa att inget dokument rörs om alla villkor inte är uppfyllda. Så antalet ökar inte om användaren redan har röstat eller minskar om deras röst faktiskt inte var närvarande längre vid tidpunkten för uppdateringen.

Naturligtvis är det inte praktiskt att läsa en array med ett par hundra poster i ett dokument tillbaka i någon annan del av din ansökan. Men MongoDB har ett väldigt standard sätt att hantera det också:

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

Denna användning av $elemMatch i projektion returnerar endast den aktuella användaren om de är närvarande eller bara en tom array där de inte är. Detta gör att resten av din applikationslogik kan vara medveten om om den aktuella användaren redan har röstat eller inte.

Det är den grundläggande tekniken och kan fungera för dig som den är, men du bör vara medveten om att inbäddade arrayer inte bör utökas oändligt, och det finns också en hård gräns på 16 MB för BSON-dokument. Så konceptet är sunt, men kan helt enkelt inte användas på egen hand om du förväntar dig 1000-tals "gilla-röster" på ditt innehåll. Det finns ett koncept som kallas "bucketing" som diskuteras i detalj i det här exemplet för Hybrid Schema-design som tillåter en lösning för att lagra en stor volym av "likes". Du kan titta på det för att använda tillsammans med de grundläggande begreppen här som ett sätt att göra detta i volym.




  1. NoSQL (MongoDB) vs Lucene (eller Solr) som din databas

  2. Åtgärda sidfel i MongoDB

  3. MongoDB Opensource vs MongoDB Enterprise

  4. Gör om viktiga namnkonventioner?