Me gustaría lograr una operación en MongoDB que sea análoga a doc.value = max(doc.value - amount, 0) . Podría hacerlo recuperando el documento, actualizando su valor y luego guardándolo, pero ¿es posible con una operación atómica evitar problemas con la sincronización de decrementos paralelos?
De hecho, es posible lograrlo con una sola operación. Todo lo que necesita es una canalización de agregación dentro de un operador de actualización.
Supongamos que tiene un documento que se ve así:
{ "key": 1, value: 30 } Desea restar x del value y, si el valor resultante es menor que cero, establezca el value en 0; de lo contrario, establezca el value que sea: x. Aquí hay un agregador de actualizaciones que necesita. En este ejemplo estoy restando 20 de value .
db.collection.update({ key: 1 }, [ { $set: { "value": { $cond: [ { $gt: [ { $subtract: [ "$value", 20 ] }, 0 ] }, { $subtract: [ "$value", 20 ] }, 0 ] } } } ])El resultado será:
{ "key": 1, "value": 10 }Pero si cambias 20 a, digamos, 44, el resultado es:
{ "key": 1, "value": 0 }Aquí hay un patio de juegos para ti: https://mongoplayground.net/p/Y9yO6v9Oca8
Felicitaciones a la respuesta de Codemonkey por proporcionar una solución utilizando canalizaciones de agregación para una transacción atómica.
Aquí hay una canalización de agregación un poco más simple que aprovecha el operador $max :
db.collection.update({}, [ { $set: { "value": { $max: [ 0, { $subtract: [ "$value", 20 ] } ] } } } ], { multi: true })La canalización establece el valor en el máximo de 0 y el resultado de la disminución.