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:
- Consulte o documento identificado para upsert.
- Se o documento existir, atualize atomicamente o documento existente.
- 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