sql >> Base de Datos >  >> NoSQL >> MongoDB

MongoDB/Mongoose ¿Cómo emparejo dos entradas de db sin conflictos?

Siguiendo con mi respuesta original , esto es nuevamente algo en lo que un pensamiento diferente puede venir en su ayuda. Y como tal, esto parece ser más una cuestión de arquitectura que decir que implementar su código "de cierta manera" será la mejor manera de hacerlo.

Según su comentario sobre eso y su pregunta aquí, parece que el problema que debe resolver es cómo ajustar el conteo de tropas para el otro usuario jugando el movimiento. Comencemos mirando los mismos datos nuevamente:

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

Haciendo el "movimiento"

Entonces, la situación aquí es que el usuario "B" acaba de hacer su movimiento y cometió 62 unidades en ese movimiento. En la publicación anterior, expliqué cómo recuperar el movimiento para el usuario "A" coincidente y, por lo tanto, puede "emparejarlos" y determinar la ganancia.

Yendo más allá, considere lo que sucedió en la solicitud. El usuario "B" envió, luego inserta el documento para su movimiento, luego vuelve a leer el correspondiente. Así que ahora mismo tienes ambos documentos en la memoria para la solicitud. Si considera los datos de la sesión, es posible que tenga algo como esto (de una manera muy breve):

{
    currentUnits: 100
}

Llamemos a eso el conteo inicial. Entonces, cuando envíe un movimiento del usuario, simplemente disminuye el conteo de tropas que tienen. Entonces, al hacer insertar de 62 tropas, el contador va a esto:

{
    currentUnits: 38
}

Esa es una buena práctica, ya que lo hace en el reconocimiento de inserción dentro del movimiento. Pero a continuación, dentro de esa devolución de llamada, vas a hacer la búsqueda como dije, y eso solo devuelve un documento. Ahora tienes la información que puedes comparar y hacer tus cálculos. El usuario "B" gana para que pueda ajustar el valor de su sesión:

{
    currentUnits: 150
}

Eso debería cubrir todo para el movimiento del usuario "B". Quitaste unidades cuando se jugaba un movimiento, emparejaste al otro jugador, luego "hiciste los cálculos" y ajustaste tus resultados. ¡Hecho! Ah, y salvaste todos los datos de la sesión en un almacén persistente, ¿verdad? Asiente, sí. Y también que los datos de la sesión están vinculados al identificador del usuario (o el usuario es, de hecho, la identificación de la sesión) para poder acceder a modificarlo.

Todo lo que queda es "notificar" al otro jugador.

Contarle la noticia a otra persona

Esta parte debe ser simple. Así que no lo estoy codificando para ti. Está utilizando socket.io para su aplicación, así que todo esto se reduce a enviar un mensaje. Eso significa que los datos que "emites" le dicen al otro usuario en el cliente que "perdieron sus tropas", como quieras tratarlo. Pero también recuerda que "quitaste" esas unidades cuando su movimiento fué enviado. En todos los casos, eso es asegurarse de que nadie pueda comprometerse más de lo que tiene.

Lo único posible de lo que hablar aquí es escala su aplicación más allá de una instancia. Por lo tanto, puede hablar felizmente con los eventos en el "nodo", todos trabajando en una instancia de servidor, pero para "escalar", necesitaría pasar mensajes entre diferentes instancias.

Una forma de manejar esto usando MongoDB puede ser con colecciones limitadas .

Aparte de lo que generalmente hacen las colecciones limitadas en la forma de mantener un conjunto tamaño para una colección de documentos, hay una cosa más que ofrecen, y es un cursor tailable . Una forma bastante atípica de crear uno con el controlador de nodo sería:

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

Las opciones completas se enumeran en el Cursor() sección de la página del manual del controlador. Puede acceder a estos métodos "nativos" en mongoose de la forma habitual.

Lo que un cursor "seguible" está configurado para hacer es "seguir" el documento "insertado por última vez" en la colección y puede sentarse y "seguir" de esta manera con una encuesta uniforme, como en:

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

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

Entonces, dentro de una construcción de este tipo, "encuentra" el documento recién insertado y pasa a su devolución de llamada interna la información que se procesará, donde "envía" mensajes a los clientes, actualiza las cosas y cualquier otra cosa que desee hacer.

Volviendo a su "solicitud" real, entonces estaría emitiendo una inserción después de "hacer sus cálculos" en la "colección limitada" separada. Querrías algo significativo por escrito como:

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

Y de nuevo, estos son simplemente inserciones Entonces configuraría un índice TTL para manejar las eliminaciones a lo largo del tiempo y al estar limitadas, las entradas antiguas se agotarían naturalmente al ser "expulsadas" de las entradas presentes en la colección.

En su lado "cliente", cada aplicación de usuario conectada realiza un seguimiento del valor "último _id" revelado. Entonces, las entradas recién insertadas son siempre mayor en valor a los anteriores "más antiguos".

Por lo tanto, hay "una forma" de usar MongoDB para crear una cola persistente que puede procesar secuencialmente para compartir el paso de mensajes entre varias instancias del servidor de aplicaciones.

Palabras finales

Con todo lo dicho para implementar un cursor "que se puede seguir" de esta manera, por mi dinero estaría usando zeromq o algo muy parecido. Pero puede encontrar el método MongoDB más adecuado para usted si no desea profundizar en otra tecnología. O tal vez su aplicación no necesita este tipo de "escalabilidad" (al menos en esta etapa) y simplemente pasar a los métodos "socket.io" dentro de la solicitud sería suficiente. Depende de ti.

Sin embargo, en gran medida, todavía parece estar "colgado" en sus conceptos de "recortar" y "eliminar". Esta fue la intención de cubrir en la última respuesta y era decir que borrar de documentos cuando se procesan no se requiere . El proceso descrito garantiza que nunca obtienes el "mismo par" de vuelta en cualquier solicitud.

Te animo a "volver a leer" esa información y entender realmente el proceso. Y pregunta si tienes dudas. De lo que se ha discutido allí, la analogía de su patrón de acceso a datos es más como "jugar una pila" que "pares coincidentes".

Entonces, lo que se le dio en respuesta, siguiendo con la lógica descrita aquí es todo debe necesitar para configurar sus patrones de acceso a datos. Su otro componente será, por supuesto, la mensajería, pero esto le da acceso a los datos que necesita.