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

MongoDB/Mongoose Come si accoppiano due voci db senza conflitti?

Facendo seguito alla mia risposta originale , anche questo è qualcosa in cui qualche pensiero diverso può venire in tuo aiuto. E in quanto tale sembra riguardare più l'architettura che il dire che l'implementazione del codice "in un certo modo" sarà il modo migliore da percorrere.

Dal tuo commento in merito e dalla tua domanda qui, sembra che il problema che devi risolvere sia come regolare il conteggio delle truppe per le altre utente che gioca la mossa. Iniziamo osservando di nuovo gli stessi dati:

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

Fare la "mossa"

Quindi la situazione qui è che l'utente "B" ha appena fatto la sua mossa e ha commesso 62 unità in quella mossa. Nel post precedente ho spiegato come recuperare la mossa per l'utente corrispondente "A", e quindi puoi "accoppiarli" e determinare la vincita.

Andando oltre, considera cosa è successo nella richiesta. L'utente "B" ha inviato, quindi inserisci il documento per il suo spostamento, quindi rileggi quello corrispondente. Quindi in questo momento hai entrambi i documenti in memoria per la richiesta. Se consideri i dati della sessione, potresti avere qualcosa del genere (in modo molto breve):

{
    currentUnits: 100
}

Chiamiamolo il conteggio iniziale. Quindi, quando invii una mossa dell'utente, decrementi semplicemente il conteggio delle truppe che ha. Quindi, quando si esegue l'inserto di 62 truppe, il contatore va a questo:

{
    currentUnits: 38
}

Questa è una buona pratica, poiché lo fai sul riconoscimento dell'inserto all'interno della mossa. Ma dopo, all'interno di quella richiamata, farai la ricerca, come ho detto, e solo restituisce un documento. Ora hai le informazioni che puoi confrontare e fare i tuoi calcoli. L'utente "B" vince così puoi modificare il valore della tua sessione:

{
    currentUnits: 150
}

Quindi dovrebbe coprire tutto per lo spostamento per l'utente "B". Hai tolto unità quando è stata giocata una mossa, hai abbinato l'altro giocatore, quindi hai "fatto i calcoli" e hai modificato i risultati. Fatto! Oh, e hai salvato tutti i dati di sessione in un archivio persistente, vero? Annuisci sì. Inoltre, i dati della sessione sono legati all'handle dell'utente (o l'utente è in effetti l'id della sessione) per poter accedere alla modifica.

Non resta che "notificare" l'altro giocatore.

Raccontare la notizia a qualcun altro

Questa parte dovrebbe essere semplice. Quindi non lo sto codificando per te. Stai utilizzando socket.io per la tua applicazione, quindi tutto questo si riduce all'invio di un messaggio. Ciò significa che i dati che "emetti" dicono all'altro utente sul client che hanno "perso le loro truppe", comunque tu voglia gestirli. Ma ricorda anche che hai "portato via" quelle unità quando le loro mosse è stato presentato. In tutti i casi ciò significa assicurarsi che nessuno possa impegnarsi più di quello che ha.

L'unica cosa possibile di cui parlare qui è ridimensionamento la tua applicazione oltre un'istanza. Quindi puoi parlare felicemente con gli eventi su "nodo" che funzionano tutti su un'istanza del server, ma per "scalare" dovresti passare i messaggi tra istanze diverse.

Un modo per gestirlo utilizzando MongoDB può essere con una raccolte limitate .

A parte ciò che generalmente fanno le raccolte limitate nel modo di tenere un set dimensione per una raccolta di documenti, c'è un'altra cosa che offrono, ed è un cursore di coda . Un modo abbastanza atipico per crearne uno con il driver del nodo sarebbe come:

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

Le opzioni complete sono elencate in Cursor() sezione della pagina del manuale del conducente. Puoi ottenere questi metodi "nativi" in mangusta nel modo tipico.

Quello che un cursore "tailable" è impostato per fare è "seguire" il documento "ultimo inserito" nella raccolta e puoi sederti e "seguire" in questo modo con un sondaggio uniforme, proprio come in:

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

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

Quindi all'interno di tale costrutto "trovi" il documento appena inserito e passi al tuo callback interno le informazioni da elaborare, dove "invii" messaggi ai clienti, aggiorni le cose e qualsiasi altra cosa tu voglia fare.

Tornando alla tua "richiesta" effettiva, rilasceresti un inserto dopo aver "fatto i tuoi calcoli" nella "raccolta limitata" separata. Vorresti qualcosa di significativo in breve come:

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

E ancora questi sono solo inserti. Quindi dovresti impostare un indice TTL per gestire le eliminazioni nel tempo ed essere limitate, le vecchie voci si esaurirebbero naturalmente venendo "espulse" dalle voci presenti nella raccolta.

Dal tuo lato "client", ogni applicazione utente connessa tiene traccia del valore "ultimo _id" ricevuto. Quindi le voci appena inserite sono sempre di valore maggiore ai precedenti "più vecchi".

Quindi c'è "un modo" per utilizzare MongoDB per creare una coda persistente che puoi elaborare in sequenza per condividere il passaggio di messaggi tra più istanze del server delle applicazioni.

Le ultime parole

Detto questo per aver implementato un cursore "tail-able" in questo modo, per i miei soldi userei zeromq o qualcosa di molto simile. Ma potresti trovare il metodo MongoDB più adatto a te se non vuoi approfondire un'altra tecnologia. O forse questo tipo di "scalabilità" non è necessaria alla tua applicazione (almeno in questa fase) e basterebbe semplicemente passare ai metodi "socket.io" all'interno della richiesta. A te.

In gran parte, però, sembri ancora "appeso" sui tuoi concetti di "paring" ed "eliminazione". Questa era l'intenzione di coprire nell'ultima risposta ed era dire che cancellazione di documenti quando vengono elaborati è non richiesto . Il processo descritto garantisce che non avrai mai la "stessa coppia" indietro a qualsiasi richiesta.

Ti incoraggio a "rileggere" quelle informazioni e capire davvero il processo. E chiedi se hai domande. Da ciò che è stato discusso lì, l'analogia del tuo modello di accesso ai dati è più simile a "giocare su uno stack" che a "coppie corrispondenti".

Quindi cosa ti è stato dato in risposta, seguire con la logica qui descritta è tutto dovresti aver bisogno per impostare i tuoi modelli di accesso ai dati. L'altro tuo componente sarà ovviamente la messaggistica, ma questo ti dà accesso ai dati di cui hai bisogno.