MongoDB: ¿qué pasa con el tipo de valor decimal?

Actualmente estoy aprendiendo y aplicando MongoDB para un pequeño proyecto relacionado con finanzas.


Cuando leo MongoDB en acción , dice:

El único otro problema que comúnmente surge con los tipos numéricos BSON es la falta de soporte decimal. Esto significa que si planea almacenar valores de moneda en MongoDB, debe usar un tipo de entero y mantener los valores en centavos.


Mi producto financiero relacionado implicará algunos valores de moneda, pero estoy un poco confundido o preocupado por la statement anterior. Aquí están mis preguntas:

  1. ¿Puedo usar el double para esos currency values en mi proyecto?
  2. ¿Qué pasará o las consecuencias si uso directamente el double para ellos?
  3. Si el tipo decimal es un elemento imprescindible para el producto financiero, ¿es una mala idea usar MongoDB?
  4. ¿Qué significa you need to use an integer type and keep the values in cents ? ¿Significa que si voy a almacenar 1.34 dollars , debo almacenar 134 cents ?

Gracias

Si desea una representación exacta para fines financieros, los valores de dobles o de coma flotante no son adecuados ya que las partes fraccionarias están sujetas a un error de redondeo. Ciertos valores decimales no pueden representarse utilizando puntos flotantes basados ​​en binarios y deben aproximarse.

Para una introducción menos técnica, vea El problema con el redondeo de los números de coma flotante ; si quieres salir geek, entonces lee lo que todo científico informático debería saber sobre la aritmética de coma flotante .

La recomendación de usar un tipo de entero (almacenar el valor en centavos) es evitar posibles errores de redondeo. Este enfoque se describe como ” Usar un factor de escala ” en la documentación de MongoDB para modelar datos monetarios y es una solución general para MongoDB 3.2 y anteriores.

MongoDB 3.4 incluye un nuevo tipo Decimal BSON que proporciona precisión exacta para manipular campos de datos monetarios.

Cuando no desee almacenar moneda como valores de centavos, puede almacenar una moneda de $ 1,34 como un objeto como este:

 { major: 1, minor: 34, currency: "USD" } 

Hacer cálculos con objetos como este no sería fácil y no usaría las reglas de redondeo comercial. Pero no debe hacer ninguna lógica comercial en la base de datos de todos modos, especialmente no cuando se trata de una base de datos “tonta” como MongoDB.

Lo que debe hacer es serializar / deserializar estos objetos desde / hacia una clase Money en su aplicación que implemente las operaciones básicas de matemáticas con respecto a las reglas de redondeo y arroje una excepción cuando intente realizar una operación con unidades monetarias diferentes ( $12.34 + 14.95€ = error – primero debe convertir una moneda a la otra moneda proporcionando una tasa de cambio).

Si está utilizando Mongoose, puede usar las funciones getter / setter en la definición de esquema, por ejemplo

 function getDecimalNumber(val) { return (val/1000000); } function setDecimalNumber(val) { return (val*1000000); } 

Aplicable a un objeto de esquema tal como

 balance: { type: Number, default: 0, get: getDecimalNumber, set: setDecimalNumber }, 

El número de ceros para multiplicar / dividir depende de la precisión que desee.

Parece que MongoDB finalmente ha agregado soporte para decimales, aunque al momento de escribir esto, este es solo el desarrollo finalizado, pero con suerte debería estar disponible muy pronto en la versión estable (3.4?).

https://jira.mongodb.org/browse/SERVER-1393

Sé que esta publicación es antigua pero ocupa un lugar destacado en Google, así que …

La mejor solución para almacenar datos financieros es utilizar la precisión exacta documentada por MongoDB ellos mismos aquí http://docs.mongodb.org/v2.6/tutorial/model-monetary-data/#monetary-value-exact-precision .

 {price: 9990, currency: "USD" } 

Y cuando necesite los datos solo divida entre 100 suponiendo que desea una precisión de 2 dígitos. La desventaja es que siempre necesita trabajar con la misma precisión.

MongoDb agregó soporte para el tipo de datos Decimal en la versión 3.4 . También está disponible desde el caparazón .

3.4 agrega soporte para el formato decimal128 con el nuevo tipo de datos decimal. El formato decimal128 admite números con hasta 34 dígitos decimales (es decir, dígitos significativos) y un rango exponencial de -6143 a +6144.

A diferencia del tipo de datos dobles, que solo almacena una aproximación de los valores decimales, el tipo de datos decimales almacena el valor exacto. Por ejemplo, un NumberDecimal decimal (“9.99”) tiene un valor preciso de 9.99 donde como un doble 9.99 tendría un valor aproximado de 9.9900000000000002131628 …