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

Erro de chave duplicada do Mongoose com upsert


Um upsert que resulta em uma inserção de documento não é uma operação totalmente atômica. Pense no upsert executando as seguintes etapas discretas:
  1. Consulte o documento identificado para upsert.
  2. Se o documento existir, atualize atomicamente o documento existente.
  3. Senão (o documento não existe), insira atomicamente um novo documento que incorpore os campos de consulta e a atualização.

Portanto, as etapas 2 e 3 são atômicas, mas outro upsert pode ocorrer após a etapa 1, portanto, seu código precisa verificar o erro de chave duplicada e tentar novamente o upsert se isso ocorrer. Nesse ponto, você conhece o documento com esse _id existe por isso sempre terá sucesso.

Por exemplo:
var minute = utils.minute();
Monitor.update({ _id: minute }, { $inc: update }, { upsert: true }, function(err) {
    if (err) {
        if (err.code === 11000) {
            // Another upsert occurred during the upsert, try again. You could omit the
            // upsert option here if you don't ever delete docs while this is running.
            Monitor.update({ _id: minute }, { $inc: update }, { upsert: true },
                function(err) {
                    if (err) {
                        console.trace(err);
                    }
                });
        }
        else {
            console.trace(err);
        }
    }
});

Consulte aqui a documentação relacionada.

Você ainda pode estar se perguntando por que isso pode acontecer se a inserção for atômica, mas o que isso significa é que nenhuma atualização ocorrerá no documento inserido até que esteja completamente escrito, não que nenhuma outra inserção de um documento com o mesmo _id pode acontecer.

Além disso, você não precisa criar manualmente um índice em _id como todas as coleções do MongoDB têm um índice exclusivo em _id sem considerar. Então você pode remover esta linha:
monitorSchema.index({_id: -1}); // Not needed