MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

MongoDB/Mongoose Como faço para emparelhar duas entradas de banco de dados sem conflitos?


Seguindo minha resposta original , isso é novamente algo em que algum pensamento diferente pode vir em seu auxílio. E, como tal, isso parece ser mais sobre arquitetura do que dizer que implementar seu código "de uma certa maneira" será o melhor caminho a seguir.

Pelo seu comentário sobre isso e sua pergunta aqui, parece que o problema que você precisa resolver é como ajustar a contagem de tropas para os outros usuário jogando o movimento. Vamos começar analisando os mesmos dados novamente:
{ "_id" : ObjectId("531cf5f3ba53b9dd07756bb7"), "user" : "A", "units" : 50 }
{ "_id" : ObjectId("531cf622ba53b9dd07756bb9"), "user" : "B", "units" : 62 }

Fazendo o "movimento"


Portanto, a situação aqui é que o usuário "B" acabou de fazer sua jogada e confirmou 62 unidades nesse movimento. No post anterior, expliquei como recuperar o movimento para o usuário correspondente "A" e, portanto, você pode "emparelhar" eles e determinar a vitória.

Levando isso adiante, considere o que aconteceu na solicitação. O usuário "B" enviou, então você insere o documento para sua mudança, então você lê de volta o correspondente. Então, agora você tem os dois documentos na memória para a solicitação. Se você considerar os dados da sessão, poderá ter algo assim (de uma maneira muito breve):
{
    currentUnits: 100
}

Vamos chamar isso de contagem inicial. Então, quando você envia um movimento do usuário, você apenas diminui a contagem de tropas que eles têm. Então, ao fazer o inserir de 62 tropas, o contador vai para isso:
{
    currentUnits: 38
}

Essa é uma boa prática, pois você faz isso na confirmação de inserção dentro do movimento. Mas em seguida, dentro desse retorno de chamada, você fará a descoberta, como eu disse, e isso somente retorna um documento. Agora você tem as informações que você pode comparar e fazer suas contas. O usuário "B" ganha para que você possa ajustar o valor da sua sessão:
{
    currentUnits: 150
}

Então, isso deve cobrir tudo para a mudança para o usuário "B". Você tirou unidades quando uma jogada foi jogada, você igualou o outro jogador, então você "fez as contas" e ajustou seus resultados. Feito! Ah, e você salvou todos os dados da sessão em um armazenamento persistente, não é? Assentir sim. E também que os dados da sessão estão vinculados ao identificador do usuário (ou o usuário é de fato o ID da sessão) para obter acesso para modificá-lo.

Tudo o que resta é "notificar" o outro jogador.

Contar a notícia a alguém


Esta parte deve ser simples. Então eu não estou codificando para você. Você está usando socket.io para seu aplicativo, então tudo isso se resume a enviar uma mensagem. Isso significa que os dados que você "emite" informam ao outro usuário no cliente que eles "perderam suas tropas", da maneira que você quiser lidar com isso. Mas lembre-se também de que você "tirou" essas unidades quando seu movimento foi submetido. Em todos os casos, isso é garantir que ninguém possa cometer mais do que tem.

A única coisa possível de se falar aqui é escalonamento seu aplicativo além de uma instância. Assim, você pode conversar alegremente com eventos no "nó" todos trabalhando em uma instância do servidor, mas para "escalar" você precisaria passar mensagens entre instâncias diferentes.

Uma maneira de lidar com isso usando o MongoDB pode ser com uma coleções limitadas .

Além do que as coleções limitadas geralmente fazem para manter um conjunto tamanho para uma coleção de documentos, há mais uma coisa que eles oferecem, e isso é um cursor tailable . Uma maneira bastante atípica de criar um com o driver de nó seria:
var options = { tailable: true, awaitdata: true, numberOfRetries: -1 };
var cursor = collection.find(query, options).sort({ $natural: 1 });

As opções completas estão listadas no Cursor() seção da página do manual do driver. Você pode obter esses métodos "nativos" no mangusto da maneira típica.

O que um cursor "tailable" está configurado para fazer é "seguir" o documento "último inserido" na coleção e você pode sentar e "seguir" dessa maneira com uma pesquisa uniforme, como em:
    (function more() {
        cursor.nextObject(handle(function(doc) {
            if (!doc) return setTimeout(poll, self.wait);

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

Então dentro de tal construção você "encontra" o documento recém inserido e passa para seu callback interno as informações a serem processadas, onde você "envia" mensagens para clientes, atualiza coisas e o que mais você quiser fazer.

De volta ao seu "pedido" real, você estaria emitindo uma inserção depois de "fazer suas contas" para a "coleção limitada" separada. Você gostaria de algo significativo por breves como:
{ "player": "B", "vsplayer": "A", "win": 50, "loss": 62 }

E, novamente, estes são apenas inserções. Então você configuraria um índice TTL para lidar com as exclusões ao longo do tempo e sendo limitadas, as entradas antigas seriam naturalmente drenadas ao serem "empurradas" das entradas presentes na coleção.

No lado do "cliente", cada aplicativo de usuário conectado mantém o controle do valor "último _id" recebido. Portanto, as entradas recém-inseridas são sempre maior em valor aos anteriores "mais antigos".

Portanto, há "uma maneira" de usar o MongoDB para criar uma fila persistente que você pode processar sequencialmente para compartilhar a passagem de mensagens entre várias instâncias do servidor de aplicativos.

Palavras Finais


Com tudo dito para implementar um cursor "tail-able" dessa maneira, pelo meu dinheiro eu estaria usando zeromq ou algo parecido. Mas você pode achar que o método MongoDB é mais adequado para você se não quiser se aprofundar em outra tecnologia. Ou talvez esse tipo de "escalabilidade" não seja necessário para seu aplicativo (pelo menos neste estágio) e simplesmente passar para os métodos "socket.io" dentro da solicitação seria suficiente. Você decide.

Em grande parte, porém, você ainda parece estar "desligado" em seus conceitos de "aparar" e "excluir". Essa foi a intenção de cobrir na última resposta e foi dizer que excluir de documentos quando são processados ​​não é obrigatório . O processo descrito garante que você nunca obtém o "mesmo par" de volta em qualquer pedido.

Recomendo que você "releia" essas informações e realmente entender o processo. E pergunte se tiver dúvidas. Pelo que foi discutido lá, a analogia do seu padrão de acesso a dados é mais como "jogar com uma pilha" do que "combinar pares".

Então, o que você recebeu em resposta, seguindo com a lógica descrita aqui é tudo você deve precisar para configurar seus padrões de acesso a dados. Seu outro componente será, obviamente, as mensagens, mas isso lhe dará acesso aos dados de que você precisa.