Eu e meus colegas encontramos uma solução alternativa. Podemos chamá-lo de inicialização em três etapas .
Lembre-se que o MongoDB garante a atomicidade das operações em um único documento. Com este fato em mente podemos operar da seguinte forma:
- Tente atualizar o documento, incrementando adequadamente os contadores em um intervalo de tempo especificado. Não faça nenhum upsert, apenas uma operação de atualização antiquada. Lembre-se de que a execução de uma instrução de atualização retorna o número de documentos gravados. Se o número de documentos escritos for maior que zero, você terminou.
- Se o número de documentos gravados pela atualização for zero, significa que o documento relativo a ser atualizado ainda não está presente na coleção. Tente inserir todo o documento para as tags especificadas. Coloque todos os contadores (valores de campo) para zero. Além disso, a execução de uma instrução de inserção retorna o número de documentos gravados. Se ele retornar zero ou lançar uma exceção, não importa:significa que algum outro processo já inseriu o documento para as mesmas tags.
- Execute a mesma atualização acima novamente.
O código deve ser semelhante ao seguinte trecho de código.
// Firt of all, try the update
var result = db.test.update(
{timestamp_minute: ISODate("2013-10-10T23:06:00.000Z"), type: “memory_used”},
{$inc: {"values.39": 1}},
{upsert: false}
);
// If the update do not succeed, then try to insert the document
if (result.nModified === 0) {
try {
db.test.insert(/* Put here the whole document */);
} catch (err) {
console.log(err);
}
// Here we are sure that the document exists.
// Retry to execute the update statement
db.test.update(/* Same update as above */);
}
O procedimento acima funciona se uma pré-condição for válida:
_id
valor deve ser derivado de outros campos no documento. Em nosso exemplo, _id
o valor seria '2013-10-10T23:06:00.000Z-memory_used
. Somente usando esta técnica, a inserção no ponto 2 falhará corretamente.