MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

MongoDB/Mongoose Wie paare ich zwei DB-Einträge ohne Konflikte?

Fortsetzung meiner ursprünglichen Antwort , dies ist wieder etwas, wo Ihnen ein anderes Denken zu Hilfe kommen kann. Und als solches scheint es hier mehr um Architektur zu gehen, als zu sagen, dass die Implementierung Ihres Codes "auf eine bestimmte Weise" der beste Weg sein wird.

Aus Ihrem Kommentar dazu und Ihrer Frage hier geht hervor, dass das Problem, das Sie lösen müssen, darin besteht, wie Sie die Anzahl der Truppen für den anderen anpassen können Benutzer, der den Zug spielt. Beginnen wir damit, uns dieselben Daten noch einmal anzusehen:

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

Den "Umzug" machen

Die Situation hier ist also, dass Benutzer „B“ gerade seinen Zug gemacht und 62 übergeben hat Einheiten in dieser Bewegung. Im vorherigen Beitrag habe ich erklärt, wie man den Zug für den passenden Benutzer „A“ zurückerhält, und daher können Sie sie „paaren“ und den Gewinn bestimmen.

Betrachten Sie weiter, was in der Anfrage passiert ist. Benutzer "B" übermittelt, dann fügen Sie das Dokument für seinen Umzug ein, dann lesen Sie das passende zurück. Sie haben also jetzt beide Dokumente für die Anfrage im Speicher. Wenn Sie die Sitzungsdaten betrachten, haben Sie vielleicht so etwas (in sehr kurzer Form):

{
    currentUnits: 100
}

Nennen wir das die Startzählung. Also, wenn Sie senden eine Bewegung des Benutzers, verringern Sie einfach die Anzahl der Truppen, die er hat. Also beim Einfügen von 62 Truppen, geht der Zähler zu diesem:

{
    currentUnits: 38
}

Das ist eine gute Übung, da Sie dies bei der Einfügungsbestätigung innerhalb des Umzugs tun. Aber als Nächstes in diesem Rückruf werden Sie, wie gesagt, suchen, und das nur gibt ein Dokument zurück. Jetzt haben Sie die Informationen, die Sie vergleichen und ausrechnen können. Benutzer "B" gewinnt, sodass Sie Ihren Sitzungswert anpassen können:

{
    currentUnits: 150
}

Das sollte also alles für den Umzug von Benutzer "B" abdecken. Sie haben Einheiten weggenommen, als ein Zug gespielt wurde, Sie haben den anderen Spieler angepasst, dann haben Sie "gerechnet" und Ihre Ergebnisse angepasst. Fertig! Oh, und du hast gespart alle Sitzungsdaten in einem dauerhaften Speicher, nicht wahr? Nick ja. Und auch diese Sitzungsdaten sind an das Benutzer-Handle gebunden (oder der Benutzer ist tatsächlich die Sitzungs-ID), um Zugang zum Ändern zu erhalten.

Alles, was übrig bleibt, ist, den anderen Spieler zu "benachrichtigen".

Anderen die Neuigkeiten erzählen

Dieser Teil sollte einfach sein. Also codiere ich es nicht für Sie. Sie verwenden socket.io für Ihre Bewerbung, so dass es nur darum geht, eine Nachricht zu senden. Das bedeutet, dass die Daten, die Sie "aussenden", dem anderen Benutzer auf dem Client mitteilen, dass sie "ihre Truppen verloren haben", wie auch immer Sie damit umgehen möchten. Aber denken Sie auch daran, dass Sie diese Einheiten "weggenommen" haben, als sie sich bewegten wurde übermittelt. In allen Fällen stellt das sicher, dass niemand mehr binden kann, als er hat.

Hier kann man nur über Skalierung sprechen Ihre Anwendung über eine Instanz hinaus. Sie können also problemlos mit Ereignissen auf "Knoten" sprechen, die alle auf einer Serverinstanz arbeiten, aber zum "Skalieren" müssten Sie Nachrichten zwischen verschiedenen Instanzen weiterleiten.

Eine Möglichkeit, dies mit MongoDB zu handhaben, sind begrenzte Sammlungen .

Abgesehen davon, was begrenzte Sammlungen im Allgemeinen tun, um ein Set zu halten Größe für eine Sammlung von Dokumenten, es gibt noch eine Sache, die sie anbieten, und das ist ein anpassbarer Cursor . Ein ziemlich untypischer Weg, einen mit dem Knotentreiber zu erstellen, wäre wie folgt:

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

Die vollständigen Optionen sind im Cursor() Abschnitt der Handbuchseite des Treibers. Sie können diese "nativen" Methoden in Mungo auf dem typischen Weg erreichen.

Ein "anpassbarer" Cursor ist so eingerichtet, dass er dem "zuletzt eingefügten" Dokument in der Sammlung "folgt", und Sie können auf diese Weise mit einer gleichmäßigen Abfrage sitzen und "folgen", ähnlich wie in:

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

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

Innerhalb eines solchen Konstrukts "finden" Sie also das neu eingefügte Dokument und übergeben die zu verarbeitenden Informationen an Ihren inneren Callback, wo Sie Nachrichten an Clients "senden", Dinge aktualisieren und was Sie sonst noch tun möchten.

Zurück zu Ihrer eigentlichen "Anfrage", dann würden Sie eine Beilage herausgeben, nachdem Sie "rechnet" haben, um die separate "gedeckelte Sammlung" zu erhalten. Sie möchten etwas Sinnvolles in Kürze wie:

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

Und das sind wiederum nur Einsätze. Sie würden also einen TTL-Index einrichten Um die Löschungen im Laufe der Zeit und die Begrenzung zu bewältigen, würden die alten Einträge natürlich entleert, indem sie aus den in der Sammlung vorhandenen Einträgen "herausgeschoben" würden.

Auf Ihrer "Client"-Seite verfolgt jede verbundene Benutzeranwendung den erhaltenen "last _id"-Wert. Die neu eingefügten Einträge sind also immer höher im Wert als die "älteren" Vorgänger.

Es gibt also „eine Möglichkeit“, mit MongoDB eine dauerhafte Warteschlange zu erstellen, die Sie nacheinander verarbeiten können, um die Nachrichtenübermittlung zwischen mehreren Anwendungsserverinstanzen zu teilen.

Schlussworte

Trotz allem, was für die Implementierung eines "Tail-fähigen" Cursors auf diese Weise gesagt wurde, würde ich für mein Geld zeromq verwenden oder so ähnlich. Aber vielleicht ist die MongoDB-Methode besser für Sie geeignet, wenn Sie nicht in eine andere Technologie eintauchen möchten. Oder vielleicht wird diese Art von „Skalierbarkeit“ von Ihrer Anwendung nicht benötigt (zumindest in diesem Stadium) und es würde ausreichen, innerhalb der Anfrage einfach an „socket.io“-Methoden zu übergeben. Bis zu Ihnen.

Im Großen und Ganzen scheinen Sie jedoch immer noch an Ihren Konzepten des "Ausschneidens" und "Löschens" festzuhalten. Dies war die Absicht, die in der letzten Antwort behandelt wurde, und sollte sagen, dass Löschen von Dokumenten, wenn sie verarbeitet werden, ist nicht erforderlich . Der beschriebene Prozess sichert dass Sie nie das "gleiche Paar" bekommen zurück auf jede Anfrage.

Ich würde Sie ermutigen, "erneut zu lesen" diese Informationen und den Prozess wirklich verstehen. Und fragen Sie, wenn Sie Fragen haben. Nach dem, was dort besprochen wurde, ähnelt die Analogie Ihres Datenzugriffsmusters eher dem "Ausspielen eines Stapels" als dem "Zusammenpassen von Paaren".

Also, was Sie als Antwort erhalten haben, weiter mit der hier beschriebenen Logik ist alles Sie benötigen sollten, um Ihre Datenzugriffsmuster einzurichten. Ihre andere Komponente wird natürlich das Messaging sein, aber das gibt Ihnen Zugriff auf die Daten, die Sie brauchen.