在Python中更新复杂的JSON对象
我正在用Python(v3.5)获取某种复杂的MongoDB文档,我应该更新其中的一些值,这些值分散在对象周围,在结构中没有特定的模式,并将其保存回不同的MongoDB集合。该对象如下所示:在Python中更新复杂的JSON对象,python,json,mongodb,python-3.x,Python,Json,Mongodb,Python 3.x,我正在用Python(v3.5)获取某种复杂的MongoDB文档,我应该更新其中的一些值,这些值分散在对象周围,在结构中没有特定的模式,并将其保存回不同的MongoDB集合。该对象如下所示: # after json.loads(mongo_db_document) my dict looks like this notification = { '_id': '570f934f45213b0d14b1256f', 'key': 'receipt', 'label': '
# after json.loads(mongo_db_document) my dict looks like this
notification = {
'_id': '570f934f45213b0d14b1256f',
'key': 'receipt',
'label': 'Delivery Receipt',
'version': '0.0.1',
'active': True,
'children': [
{
'key': 'started',
'label': 'Started',
'children': [
'date',
'time',
'offset'
]
},
{
'key': 'stop',
'label': 'Ended',
'children': [
'date',
'time',
'offset'
]
},
{
'label': '1. Particulars',
'template': 'formGroup',
'children': [
{
'children': [
{
'key': 'name',
'label': '2.1 Name',
'value': '********** THIS SHOULD BE UPDATED **********',
'readonly': 'true'
},
{
'key': 'ims_id',
'label': '2.2 IMS Number',
'value': '********** THIS SHOULD BE UPDATED **********',
'readonly': 'true'
}
]
},
{
'children': [
{
'key': 'type',
'readonly': '********** THIS SHOULD BE UPDATED **********',
'label': '2.3 Type',
'options': [
{
'label': 'Passenger',
'value': 'A37'
},
{
'label': 'Cargo',
'value': 'A35'
},
{
'label': 'Other',
'value': '********** THIS SHOULD BE UPDATED **********'
}
]
}
]
}
]
},
{
'template': 'formGroup',
'key': 'waste',
'label': '3. Waste',
'children': [
{
'label': 'Waste',
'children': [
{
'label': 'Plastics',
'key': 'A',
'inputType': 'number',
'inputAttributes': {
'min': 0
},
'value': '********** THIS SHOULD BE UPDATED **********'
},
{
'label': 'B. Oil',
'key': 'B',
'inputType': 'number',
'inputAttributes': {
'min': 0
},
'value': '********** THIS SHOULD BE UPDATED **********'
},
{
'label': 'C. Operational',
'key': 'C',
'inputType': 'number',
'inputAttributes': {
'min': 0
},
'value': '********** THIS SHOULD BE UPDATED **********'
}
]
}
]
},
{
'template': 'formRow',
'children': [
'empty',
'signature'
]
}
],
'filter': {
'timestamp_of_record': [
'date',
'time',
'offset'
]
}
}
我最初的想法是在需要更新值的地方放置占位符(如$var_name
),并用Python的string.Template
加载字符串,但不幸的是,由于某种原因,这种方法会破坏同一MongoDB文档的其他用户的很多内容
是否有一种解决方案可以简单地修改此类对象,而无需“硬编码”路径来查找需要更新的值?向JSON对象添加另一个列表。该列表中的每一项都是导致值更改的键列表。一个这样的列表的例子是:
['children',2',children',children',0',value']
。
然后,要访问该值,可以使用循环:
def change(json, path, newVal):
cur = json
for key in path[:-1]:
cur = cur[key]
cur[path[-1]] = newVal
path = notification['paths'][0]
#path, for example, could be ['children', 2, 'children', 'children', 0, 'value']
newVal = 'what ever you want'
change(notification, path, newVal)
不确定我是否理解正确,但这将动态查找所有键“value”和“readonly”,并打印出地址字段的路径
def findem(data, trail):
if isinstance(data, dict):
for k in data.keys():
if k in ('value', 'readonly'):
print("{}['{}']".format(trail, k))
else:
findem(data[k], "{}['{}']".format(trail, k))
elif isinstance(data, list):
for k in data:
findem(k, '{}[{}]'.format(trail, data.index(k)))
if __name__ == '__main__':
findem(notification, 'notification')
notification['children'][2]['children'][0]['children'][0]['readonly']
notification['children'][2]['children'][0]['children'][0]['value']
notification['children'][2]['children'][0]['children'][1]['readonly']
notification['children'][2]['children'][0]['children'][1]['value']
notification['children'][2]['children'][1]['children'][0]['readonly']
notification['children'][2]['children'][1]['children'][0]['options'][0]['value']
notification['children'][2]['children'][1]['children'][0]['options'][1]['value']
notification['children'][2]['children'][1]['children'][0]['options'][2]['value']
notification['children'][3]['children'][0]['children'][0]['value']
notification['children'][3]['children'][0]['children'][1]['value']
notification['children'][3]['children'][0]['children'][2]['value']
有一个我几年前写的小脚本——我用它在一些非常长且令人不安的JSON中查找条目。诚然,它并不漂亮,但对你来说也许会有所帮助?
您可以在Bitbucket上找到脚本(这是代码)。 不幸的是,它没有记录在案;我想当时我并不真的相信其他人会使用它。
无论如何,如果您想尝试,请将脚本保存在工作目录中,然后使用以下方法:
from RecursiveSearch import Retriever
def alter_data(json_data, key, original, newval):
'''
Alter *all* values of said keys
'''
retr = Retriever(json_data)
for item_no, item in enumerate(retr.__track__(key)): # i.e. all 'value'
# Pick parent objects with a last element False in the __track__() result,
# indicating that `key` is either a dict key or a set element
if not item[-1]:
parent = retr.get_parent(key, item_no)
try:
if parent[key] == original:
parent[key] = newval
except TypeError:
# It's a set, this is not the key you're looking for
pass
if __name__ == '__main__':
alter_data(notification, key='value',
original = '********** THIS SHOULD BE UPDATED **********',
newval = '*UPDATED*')
不幸的是,正如我所说,脚本没有很好的文档记录,因此如果您想尝试它并需要更多信息,我很乐意提供它。您是在问如何动态查找这些值的路径吗?我知道,出于某种原因,您无法再次加载、修改并保存为json?@C14L是的,你可以这样表述我的问题:)我可以写一个函数,它将贯穿整个dict并寻找每一种可能性,但我在想是否有更简单的解决方案?你能提供更多细节吗?也许是一个例子?对于这种“假设性”问题,不可能找到答案。@Roberto是的,同一个对象在JavaScript和PostgreSQL中使用,并且在另一端进行解析,因此在此时放置像
$var\u name
这样的占位符非常棘手。这看起来很有趣。我将尝试使用它,并在成功或失败后返回报告:)请返回@errata:)PS:您还可以使用父元素
进一步验证该值是否需要更新,即仅当它还包含标签
键或其他检查时才更新。