Reputation: 6055
I'm playing around with the new mongodb data type NumberDecimal
. I generally build scientific apps requiring exact precision (or as exact as possible) so I'm wondering how I can use it.
One of the apps I'm building is a python flask app which pulls data from a database and performs a variety of calculations. However, when I pull a NumberDecimal
from mongodb (let's say NumberDecimal('24.55')
) and try to add it to a add it to a bson.decimal128.Decimal128
number I created in python I get the following error:
TypeError: unsupported operand type(s) for +: 'Decimal128' and 'Decimal128'
And if I try to convert NumberDecimal
to decimal.Decimal
(or anything else):
TypeError: Cannot convert Decimal128('24.55') to Decimal
So I guess I have a few questions: (1) is there anyway to convert this NumberDecimal
to anything I can use in python, (2) if not, is there a datatype I can convert all of my other numbers to that's compatible with NumberDecimal
, (3) if not, seems to me the only way I can use it would be server-side using the aggregation framework (are there other use cases)?
Upvotes: 5
Views: 8667
Reputation: 10530
It seems you need to cast Decimal128 instances to standard Python decimals in order to operate them. But you should do that inside a context created by create_decimal128_context
, from bson.decimal128
, to ensure results can later be stored in the database.
>>> from bson.decimal128 import Decimal128, create_decimal128_context
>>> import decimal
>>>
>>> D128_CTX = create_decimal128_context()
>>>
>>> with decimal.localcontext(D128_CTX):
... d1 = Decimal128('1.23')
... d2 = Decimal128('3.21')
... d3 = Decimal128(d1.to_decimal() + d2.to_decimal())
...
>>> print(d3, type(d3))
4.44 <class 'bson.decimal128.Decimal128'>
>>> print(d3.to_decimal(), type(d3.to_decimal()))
4.44 <class 'decimal.Decimal'>
>>> decimal.Decimal(d3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: conversion from Decimal128 to Decimal is not supported
And, as you can see by the last two commands above, to cast to Python's Decimal type, use the Decimal128.to_decimal method. Do not attempt to pass a Decimal128 instance in the Decimal constructor.
Tested on Python 3.6 and pymongo 3.4.
Inspired on pymongo's documentation of the bson.decimal128
module.
Upvotes: 8