Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PyMongo SON Manipulator/transform not working (mongodb)

I'm trying to use a manipulator to convert decimal to float before saving to MongoDB. The data is coming from a SQL Server database, and I'm importing using pymssql, which is based of freeTDS.

I've followed the instructions from MongoDB docs, but I keep getting the error:

File "build\bdist.win32\egg\pymongo\collection.py", line 467, in insert_one
File "build\bdist.win32\egg\pymongo\collection.py", line 430, in _insert
bson.errors.InvalidDocument: Cannot encode object: Decimal('5019.13')

Here is my code for the transform:

import decimal
class Transform(SONManipulator):
    def transform_incoming(self, son, collection):
        for (key, value) in son.items():
            if isinstance(value, decimal.Decimal):
                son[key] = float(value)
            elif isinstance(value, dict):
                son[key] = self.transform_incoming(value, collection)
        return son

where I add it to db:

def get(collection):
    client = MongoClient(uri)
    db = client[database]
    db.add_son_manipulator(Transform())
    return db[collection]

and when I call

collection = get('mycollection')
collection.insert_one(object)
like image 669
Lucas Avatar asked Dec 05 '25 11:12

Lucas


1 Answers

According to MongoDB Changelog, since MongoDB 3.0, SONManipulator API is deprecated and won't work on db.insert_one():

The SONManipulator API has limitations as a technique for transforming your data. Instead, it is more flexible and straightforward to transform outgoing documents in your own code before passing them to PyMongo, and transform incoming documents after receiving them from PyMongo.

Thus the add_son_manipulator() method is deprecated. PyMongo 3’s new CRUD API does not apply SON manipulators to documents passed to bulk_write(), insert_one(), insert_many(), update_one(), or update_many(). SON manipulators are not applied to documents returned by the new methods find_one_and_delete(), find_one_and_replace(), and find_one_and_update().

It would however work on db.insert(), but it's being deprecated, too.

So you're better off writing your custom converter on the boundary between your applied code and the database.

like image 149
user15108 Avatar answered Dec 07 '25 10:12

user15108



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!