sql >> Databasteknik >  >> NoSQL >> MongoDB

MongoDB/Mongoose Hur parar jag två db-poster utan konflikter?

Efter mitt ursprungliga svar , detta är återigen något där ett annat tänkande kan komma till din hjälp. Och som sådant verkar det här handla mer om arkitektur än att säga att implementering av din kod "på ett visst sätt" kommer att vara det bästa sättet att gå.

Från din kommentar om det och din fråga här verkar det som att problemet du behöver lösa är hur man justerar antalet trupper för de andra användare som spelar draget. Låt oss börja med att titta på samma data igen:

{ "_id" : ObjectId("531cf5f3ba53b9dd07756bb7"), "user" : "A", "units" : 50 }
{ "_id" : ObjectId("531cf622ba53b9dd07756bb9"), "user" : "B", "units" : 62 }

Gör "flytten"

Så situationen här är att användare "B" precis har gjort sitt drag och begått 62 enheter i det draget. I det föregående inlägget förklarade jag hur man får tillbaka draget för den matchande användaren "A", och därför kan du "para ihop" dem och avgöra vinsten.

Med det längre, överväg vad som hände i begäran. Användare "B" skickade in, sedan infogar du dokumentet för deras flytt, sedan läser du tillbaka det matchande. Så just nu har du båda dokumenten i minnet för begäran. Om du tar hänsyn till sessionsdata, kan du ha något liknande detta (på ett mycket kortfattat sätt):

{
    currentUnits: 100
}

Låt oss kalla det starträkningen. Så när du skicka in ett drag från användaren minskar du bara antalet trupper de har. Så när du gör insättningen av 62 trupper, räknaren går till detta:

{
    currentUnits: 38
}

Det är bra praxis, eftersom du gör det vid insättningsbekräftelsen under flytten. Men nästa inuti den återuppringningen ska du göra fyndet som jag sa, och det bara returnerar ett dokument. Nu har du informationen som du kan jämföra och räkna ut. Användare "B" vinner så att du kan justera ditt sessionsvärde:

{
    currentUnits: 150
}

Så det borde täcka allt för flytten för användare "B". Du tog bort enheter när ett drag spelades, du matchade den andra spelaren, sedan "gjorde du matten" och justerade dina resultat. Gjort! Åh, och du sparade alla sessionsdata i en beständig butik, eller hur? Nicka ja. Och även att sessionsdata är knuten till användarhandtaget (eller användaren är i själva verket sessions-id) för att få tillgång till att ändra det.

Allt som återstår är att "notifiera" den andra spelaren.

Berätta nyheterna för någon annan

Denna del ska vara enkel. Så jag kodar det inte åt dig. Du använder socket.io för din ansökan, så allt detta handlar om är att skicka ett meddelande. Det betyder att data du "avger" talar om för den andra användaren på klienten att de "förlorat sina trupper", hur du än vill hantera det. Men kom också ihåg att du "tog bort" dessa enheter när de flyttade lämnades in. I alla fall är det att se till att ingen kan begå mer än vad de har.

Det enda möjliga att prata om här är skalning din ansökan utöver en instans. Så du kan prata glatt med händelser på "nod" som alla fungerar på en serverinstans, men för att "skala" måste du skicka meddelanden mellan olika instanser.

Ett sätt att hantera detta med MongoDB kan vara med en begränsad samling .

Bortsett från vad begränsade samlingar i allmänhet gör på sättet att hålla ett set storlek för en samling dokument, det finns en sak till som de erbjuder, och det är en tailable cursor . Ett ganska atypiskt sätt att skapa en med noddrivrutinen skulle vara som:

var options = { tailable: true, awaitdata: true, numberOfRetries: -1 };
var cursor = collection.find(query, options).sort({ $natural: 1 });

De fullständiga alternativen listas i Cursor() avsnittet på sidan för drivrutinen. Du kan komma åt dessa "inhemska" metoder i mongoose på det typiska sättet.

Vad en "tailable" markör är inställd för att göra är att "följa" det "senast infogade" dokumentet i samlingen och du kan sitta och "följa" på detta sätt med en jämn omröstning, ungefär som i:

    (function more() {
        cursor.nextObject(handle(function(doc) {
            if (!doc) return setTimeout(poll, self.wait);

            callback(doc);
            latest = doc._id;
            more();
        }));
    })();

Så inom en sådan konstruktion "hittar" du det nyligen infogade dokumentet och skickar till ditt inre återuppringning informationen som ska bearbetas, där du "sänder" meddelanden till kunder, uppdaterar saker och vad du än vill göra.

Tillbaka till din faktiska "begäran", då skulle du utfärda en bilaga efter att du "gjort din matte" till den separata "begränsade samlingen". Du skulle vilja ha något meningsfullt genom kortfattat som:

{ "player": "B", "vsplayer": "A", "win": 50, "loss": 62 }

Och återigen är dessa bara skär. Så du skulle skapa ett TTL-index för att hantera raderingarna över tid och med ett tak, skulle de gamla posterna naturligtvis tömmas genom att "skjutas ut" från de poster som finns i samlingen.

På din "klient"-sida håller varje ansluten användarapplikation reda på det "senaste _id"-värdet som visas. Så de nyligen infogade posterna är alltid högre i värde än de "äldre" tidigare.

Så det finns "ett sätt" att använda MongoDB för att skapa en beständig kö som du kan bearbeta sekventiellt för att dela meddelanden som passerar mellan flera applikationsserverinstanser.

Slutord

Med allt sagt för att implementera en "tail-able" markör på detta sätt, för mina pengar skulle jag använda zeromq eller något liknande. Men du kanske tycker att MongoDB-metoden är mer lämpad för dig om du inte vill fördjupa dig i en annan teknik. Eller så kanske den här typen av "skalbarhet" inte behövs av din applikation (åtminstone i detta skede) och att bara överföra till "socket.io"-metoder inom begäran skulle vara tillräckligt. Upp till dig.

Till stor del verkar du fortfarande vara "hängd" på dina begrepp om "parning" och "radera". Detta var avsikten att täcka i det senaste svaret och var att säga att radera av dokument när de behandlas är inte obligatoriskt . Processen som beskrivs säkrar att du aldrig får "samma par" tillbaka på varje begäran.

Jag skulle uppmuntra dig att "läsa igen" den informationen och verkligen förstå processen. Och fråga om du har frågor. Från det som har diskuterats där är analogin med ditt dataåtkomstmönster mer som att "spela av en stack" än "matcha par".

Så vad du fick som svar, följer på med logiken som beskrivs här är allt du borde behöva för att ställa in dina dataåtkomstmönster. Din andra komponent kommer naturligtvis att vara meddelandet, men detta ger dig tillgång till den data du behöver.




  1. skiftlägeskänslig fråga på mongodb

  2. Ta bort data från ett mongodokument med PHP

  3. Filtrera efter land och fritextsök mongodb med mongoose

  4. mongoose:befolka i mongoose som inte har något ObjectId