2011-12-01 80 views
25

He estado buscando una manera de crear una declaración de actualización que tomará un campo numérico existente y lo modificará mediante una expresión. Por ejemplo, si tengo un campo llamado Price, ¿es posible hacer una actualización que establezca Precio a 50% de descuento sobre el valor existente?Multiplicar campo por valor en Mongodb

Así que, dado { Price : 19.99 }

me gustaría hacer db.collection.update({tag : "refurb"}, {$set {Price : Price * 0.50 }}, false, true);

se puede hacer esto o tengo para leer el valor de vuelta al cliente, modificar, a continuación, actualizar? Supongo que la pregunta entonces es si las expresiones pueden usarse en la actualización, y pueden hacer referencia al documento que se está actualizando.

+3

Tenga en cuenta que en una próxima versión de mongo, puede hacerlo sin todo esto eval y DB bloqueo casi sin costo . Compruebe y se puede aceptar la nueva respuesta, para que los nuevos desarrolladores no utilicen información obsoleta. –

Respuesta

34

Puede ejecutar el código del lado del servidor con db.eval().

db.eval(function() { 
    db.collection.find({tag : "refurb"}).forEach(function(e) { 
     e.Price = e.Price * 0.5; 
     db.collection.save(e); 
    }); 
}); 

Tenga en cuenta que esto bloqueará el DB, por lo que es mejor hacer el par de operación de búsqueda y actualización.

Ver http://www.mongodb.org/display/DOCS/Server-side+Code+Execution

+0

Gracias. ¿Estás diciendo que debería usar eval() como has mostrado, o deberías hacerlo desde el lado del cliente con find/update para evitar el bloqueo? – Brad

+1

@Brad debe evaluar el costo total de esta operación de actualización en particular. Si la operación va a ser larga (muchos documentos en las colecciones se actualizarán) nunca debe usar eval. No hay grandes gastos generales para consultar primero un documento y luego actualizarlo en lugar de actualizar en el lugar. Especialmente si limita los campos consultados para documentos grandes y utiliza la función de índice cubierto (http://www.mongodb.org/display/DOCS/Retrieving+a+Subset+of+Fields#RetrievingaSubsetofFields-CoveredIndexes) – pingw33n

+1

Genial, gracias. Veo también que eval() no funciona con sharding, por lo que eso me lo descarta a largo plazo. Nolock es una adición interesante. – Brad

-1

Bueno, esto es posible con una operación atómica como $ set.

tiene varias opciones:

  • utilizar la solución de eval() propuesto por pingw33n
  • recuperar el documento que desea modificar para obtener el valor actual y modificarlo con un conjunto
  • si tener una tasa de operación alta, es posible que desee asegurarse de que el focument no haya cambiado durante la recuperación de su valor (utilizando la solución anterior), por lo que es posible que desee utilizar una operación findAndModify (consulte this page para obtener información sobre cómo hacerlo).

Realmente depende de su contexto: con una presión muy baja en el DB, buscaría la solución de pingw33n. Con una tasa de operación muy alta, usaría la tercera solución.

+0

Gracias.No veo cómo findAndModify permitiría el uso de una expresión, que era mi objetivo principal. – Brad

+0

@Brad findAndModify permite usar la expresión pero permite realizar una acción de dos fases: primero buscar el elemento y luego actualizarlo (con su reducción del 50%) solo si no ha cambiado desde que lo recuperé – kamaradclimber

19

En el nuevo Mongo 2.6.x hay un $mul operator. Multiplicaría el valor del campo por el número con la siguiente sintaxis.

{ 
    $mul: { field: <number> } 
} 

Así, en su caso, tendrá que hacer lo siguiente:

db.collection.update(
    { tag : "refurb"}, 
    { $mul: { Price : 0.5 } } 
); 
+1

No tengo suficiente representante para comentar, de lo contrario, esto sería un comentario sobre la publicación anterior por Salvador Dalí que me ayudó pero tiene el formato incorrecto. En realidad debería ser: {$ mul: {campo: }} No {campo: {$ mul: }} – Wake

Cuestiones relacionadas