msiemens / tinydb

TinyDB is a lightweight document oriented database optimized for your happiness :)
https://tinydb.readthedocs.org
MIT License
6.75k stars 536 forks source link

Can I choose to save the json in order? #124

Closed fuzihaofzh closed 7 years ago

fuzihaofzh commented 7 years ago

I use collections.OrderedDict to sotre my key-value pair in order. But I found that when it is written to the disk, the order is wrong. I checked the code and found that the json save the data directly. Could you please add 'object_pairs_hook=collections.OrderedDict' to keep the order in the json read and write module?

msiemens commented 7 years ago

I think the way to go here is to create your own version of JSONStorage. You could start by copying the code from tinydb/storages.py to your own class, adapt it to your needs and use it instead of JSONStorage:

db = TinyDB('filename.db', storage=CustomJSONStorage)

Does that work for you?

eugene-eeo commented 7 years ago

@maplewizard revisiting this issue after a while. I dug around the Python JSON library and discovered the object_pairs_hook argument that you can supply to json.loads / json.load in order to get a chance to transform JSON objects into whatever you want.

object_pairs_hook is an optional function that will be called with the result of any object literal decoded with an ordered list of pairs. The return value of object_pairs_hook will be used instead of the dict.

Example (note that nested objects will all be transformed into OrderedDicts). This should be less expensive than passing sort_keys=True to json.dumps.

>>> import json
>>> from collections import OrderedDict
>>> u = json.loads('{"a":1, "b":[]}', object_pairs_hook=OrderedDict)
>>> u
OrderedDict([('a', 1), ('b', [])])
>>> json.dumps(u)
'{"a": 1, "b": []}'

I even checked the implementation of json.dumps to make sure that it respects whatever order the keys are given by the object being encoded (dumped).

msiemens commented 7 years ago

Closing due to inactivity. If it's still an issue, feel free to re-open.