2016-05-06 5 views
3

私はPython(v3.5)で複雑なMongoDBドキュメントを取得しています。オブジェクト内に散在していて、構造内に特定のパターンがなく、別のMongoDBコレクションに戻ります。オブジェクトは、次のようになります。Pythonで複雑なJSONオブジェクトを更新する

# 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文書の他のユーザ。

私は更新する必要がある値を見つけるために "ハードコーディング"パスなしでこの種のオブジェクトを単純に変更するソリューションがありますか?

+0

これらの値のパスを動的に見つける方法を尋ねていますか? – C14L

+0

何らかの理由でjsonとして再度ロード、変更、保存することはできません。 – Roberto

+0

@ C14Lまあ、そうですね、あなたは私の質問をそのように公式化することができます:)私はすべてのdictを通ってそれぞれの可能性を探す関数を書くことができますが、 – errata

答えて

0

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) 
+0

これは面白そうだ。私はそれをちょっと試してみるつもりだし、成功か失敗の後に戻って報告するでしょうか? – errata

+0

OK、幸運:) –

1

わからないが、これは、動的に「価値」と「読み取り専用」のすべてのキーを見つけて、パスがフィールドに対処するためにプリントアウトされます: その後、値にアクセスするために、あなたはループを使用することができます。

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'] 
1

私は数年前に書かれたこの小さなスクリプトがあります - 私はいくつかの非常に長いと狼狽JSONsのエントリを見つけるためにそれを使用。確かにそれは美しいものではありませんが、おそらくあなたの場合に役立つでしょうか?
スクリプトはBitbucket here(およびhereはコード)で見つけることができます。 残念ながら、それは文書化されていません。当時、私は他の人が使っているとは思っていませんでした。とにかく
、あなたは、それを試して、あなたの作業ディレクトリにスクリプトを保存してから、このようなものを使用したい場合は:あなたがしたい場合ので、私はスクリプトが十分に文書化されていないと述べたとして残念ながら

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*') 

をそれを試して、より多くの情報が必要な場合は、私はそれを提供してうれしいです。

+0

PS:値を更新する必要があることをさらに検証するために 'parent'要素を使うこともできますつまり、 'label'キーやその他のチェックが含まれている場合にのみ更新されます。 – Roberto

関連する問題