Johnny Metz
Johnny Metz

Reputation: 6055

MongoDB NumberDecimal: unsupported operand type(s) for +: 'Decimal128' and 'Decimal128'

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

Answers (1)

Rafa Viotti
Rafa Viotti

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

Related Questions