I have Flask app using MongoDB. I've had problems with encoding ObjectId, datetime and date objects, but solved them with this https://stackoverflow.com/a/51773611/9472066 answer - custom encoder works. I don't know, however, how to write a decoder for PyMongo: how can I know whether the string is ObjectId, or datetime, or anything else? Do I have to check format by hand in the decoder method, and then call the appropriate constructor? Or is there any smarter, more automatic way?
Asked
Active
Viewed 446 times
0
-
Where is your data coming from? – Belly Buster Apr 09 '20 at 07:58
-
@BellyBuster from my own serialization to the database. Precisely, frontend passes JSONs, I create objects from them, do a bunch of business logic operations on it, and then serialize them to database. Later I want to take them from the database. So I have both serialization and deserialization to JSON. Documents and objects are complex (embedded documents, lists of custom objects etc.), so I thing encoder and decoder are necessary, e. g. for ObjectID type. – qalis Apr 09 '20 at 08:35
1 Answers
1
I'd strongly advise you to work with native python types because pymongo will do all the heavy lifting in terms of creating the appropriate types.
It's a mistake to think MongoDB is a JSON database, and a bigger mistake to think you have to work with JSON to get data in and out out it.
If you really want to do it try the bson.json_util
module:
import pymongo
import bson.json_util
db = pymongo.MongoClient()["mydatabase"]
db.mycollection.insert_one({'a': 'a'})
json_str = bson.json_util.dumps(db.mycollection.find_one({'a': 'a'}))
json_dict = json.loads(json_str)
json_dict['a'] = 'b'
json_str = json.dumps(json_dict)
db.newcollection.insert_one(bson.json_util.loads(json_str))
print(list(db.newcollection.find({})))
But I would prefer to do this natively:
db.mycollection.insert_one({'a': 'a'})
record = db.mycollection.find_one({'a': 'a'})
record['a'] = 'b'
db.newcollection.insert_one(record)
print(list(db.newcollection.find({})))

Belly Buster
- 8,224
- 2
- 7
- 20
-
The problem with second approach in my case is that I have quite complex business logic to do with the data from the database. For example, I create User class objects with a bunch of methods and dependencies, and I have to save it to database and later load data and create User object from it. At the same time, I don't want (and with existing APIs probably can't) use PyMODM and it's Field types like StringField. Doing all work on straight dicts would be quite hard in my case, so I want to work with custom classes, which AFAIK require encoder and decoder. – qalis Apr 09 '20 at 13:25
-
You can use the class's built-in __dict__ property to get the dictionary representation of any class object. Believe me you will save a world of pain avoiding pickling and unpickling everything to JSON. – Belly Buster Apr 09 '20 at 13:32
-
What do you think about the slight workaround: classes holding JSONs, with methods for JSON access and for business logic? That would work with your second code, if I use that embedded JSON? – qalis Apr 09 '20 at 14:39
-
1
-
The `dict` property I referenced earlier should have been `__dict__`. The default formatter didn't display it properly. – Belly Buster Apr 10 '20 at 01:09