Home > database >  Python: Looping through a dictionary (created from JSON) to create row(s)
Python: Looping through a dictionary (created from JSON) to create row(s)

Time:01-07

So, I'm attempting to import Dynatrace data through an api call which returns JSON. I have the JSON imported as a dictionary of dictionaries and lists (multiple nests).

What I'm trying to do is end up with rows that I can later use to write to a csv.

I think it'll make more sense with examples.

Example of imported JSON (cut short for space, but I left 3 "sections" of what I need):

dtrace_results = json.loads(http_response.content)

which looks like:

{'totalCount': 41, 'nextPageKey': None, 
 'result': [{'metricId': 'builtin:service.response.time', 
             'data': [{'dimensions': ['SERVICE-039D18D190DF8EE1'], 
                       'dimensionMap': {'dt.entity.service': 'SERVICE-039D18D190DF8EE1'}, 
                       'timestamps': [1641491760000, 1641491820000, 1641491880000], 
                       'values': [733, None, 724]}, 
                      {'dimensions': ['SERVICE-CF6C91BB030BB3AC'], 
                       'dimensionMap': {'dt.entity.service': 'SERVICE-CF6C91BB030BB3AC'}, 
                       'timestamps': [1641491760000, 1641491820000, 1641491880000], 
                       'values': [60951.354609929076, 56788.070796460175, 57866.69565217391]}, 
                      {'dimensions': ['SERVICE-BF03689183860CA9'], 
                       'dimensionMap': {'dt.entity.service': 'SERVICE-BF03689183860CA9'}, 
                       'timestamps': [1641491760000, 1641491820000, 1641491880000], 
                       'values': [69, 74, 78.5]}
                     ]}]}

After some manipulation to get it closer to where i want it:

for row in dtrace_results['result'][0]['data']:
    row.pop('dimensions')

results of printing the above: (bullets added for clarity)

  • {'dimensionMap': {'dt.entity.service': 'SERVICE-039D18D190DF8EE1'}, 'timestamps': [1641492060000, 1641492120000, 1641492180000, 1641492240000], 'values': [None, 1495.3333333333333, 1451.5, None]}
  • {'dimensionMap': {'dt.entity.service': 'SERVICE-CF6C91BB030BB3AC'}, 'timestamps': [1641492060000, 1641492120000, 1641492180000, 1641492240000], 'values': [70568.0193548387, 64320.80487804878,55929.954545454544, 57868.15151515151]}
  • {'dimensionMap': {'dt.entity.service': 'SERVICE-BF03689183860CA9'}, 'timestamps': [1641492060000, 1641492120000, 1641492180000, 1641492240000], 'values': [132, 101, 81, 77]}

what I'm trying to get from the above is basically, in this example 4 rows for each row above, like this (numbers added just for clarity, not needed in results):

  1. SERVICE-039D18D190DF8EE1,1641492060000,None
  2. SERVICE-039D18D190DF8EE1,1641492120000,1495.3333333333333
  3. SERVICE-039D18D190DF8EE1,1641492180000,1451.5
  4. SERVICE-039D18D190DF8EE1,1641492240000,None
  5. ...followed by additional rows

Thanks in advance for any help.

CodePudding user response:

If you're trying create a list of lists given in bullet points, you're almost there. Simply iterate over dtrace_results['result'][0]['data'] (since it's a list of dictionaries) and get the relevant values via another iteration by zipping the 3 lists. Note that since row['dimensionMap']['dt.entity.service'] is not a list, we'll have to make it a list.

out = []
for row in dtrace_results['result'][0]['data']:
    
    ts = row['timestamps']
    # we need to make 'service' a list of the same length as the other lists 
    service = [row['dimensionMap']['dt.entity.service']]*len(ts) 
    vals = row['values']
    
    for zipped in zip(service, ts, vals):
        out.append(list(zipped))

Output:

[['SERVICE-039D18D190DF8EE1', 1641491760000, 733],
 ['SERVICE-039D18D190DF8EE1', 1641491820000, None],
 ['SERVICE-039D18D190DF8EE1', 1641491880000, 724],
 ['SERVICE-CF6C91BB030BB3AC', 1641491760000, 60951.354609929076],
 ['SERVICE-CF6C91BB030BB3AC', 1641491820000, 56788.070796460175],
 ['SERVICE-CF6C91BB030BB3AC', 1641491880000, 57866.69565217391],
 ['SERVICE-BF03689183860CA9', 1641491760000, 69],
 ['SERVICE-BF03689183860CA9', 1641491820000, 74],
 ['SERVICE-BF03689183860CA9', 1641491880000, 78.5]]

CodePudding user response:

Using zip and csv will get you there I think.

Given your data like:

data = {
    'totalCount': 41,
    'nextPageKey': None,
    'result': [
        {
            'metricId': 'builtin:service.response.time',
            'data': [
                {
                    'dimensions': ['SERVICE-039D18D190DF8EE1'],
                    'dimensionMap': {'dt.entity.service': 'SERVICE-039D18D190DF8EE1'},
                    'timestamps': [1641491760000, 1641491820000, 1641491880000],
                    'values': [733, None, 724]
                },
                {
                    'dimensions': ['SERVICE-CF6C91BB030BB3AC'],
                    'dimensionMap': {'dt.entity.service': 'SERVICE-CF6C91BB030BB3AC'},
                    'timestamps': [1641491760000, 1641491820000, 1641491880000],
                    'values': [60951.354609929076, 56788.070796460175, 57866.69565217391]
                },
                {
                    'dimensions': ['SERVICE-BF03689183860CA9'],
                    'dimensionMap': {'dt.entity.service': 'SERVICE-BF03689183860CA9'},
                    'timestamps': [1641491760000, 1641491820000, 1641491880000],
                    'values': [69, 74, 78.5]
                },
                ## many more
            ]
        }
    ]
}

We might try:

results = []
for item in data["result"][0]["data"]:
    dimension = item["dimensions"][0]
    for timestamp, value in zip(item["timestamps"], item["values"]):
        results.append({
            "ID": dimension,
            "timestamp": timestamp,
            "value": value if value else "None"
        })

this would allow us to do:

print(results)

giving:

[
    {'ID': 'SERVICE-039D18D190DF8EE1', 'timestamp': 1641491760000, 'value': 733},
    {'ID': 'SERVICE-039D18D190DF8EE1', 'timestamp': 1641491820000, 'value': 'None'},
    {'ID': 'SERVICE-039D18D190DF8EE1', 'timestamp': 1641491880000, 'value': 724},
    {'ID': 'SERVICE-CF6C91BB030BB3AC', 'timestamp': 1641491760000, 'value': 60951.354609929076},
    {'ID': 'SERVICE-CF6C91BB030BB3AC', 'timestamp': 1641491820000, 'value': 56788.070796460175},
    {'ID': 'SERVICE-CF6C91BB030BB3AC', 'timestamp': 1641491880000, 'value': 57866.69565217391},
    {'ID': 'SERVICE-BF03689183860CA9', 'timestamp': 1641491760000, 'value': 69},
    {'ID': 'SERVICE-BF03689183860CA9', 'timestamp': 1641491820000, 'value': 74},
    {'ID': 'SERVICE-BF03689183860CA9', 'timestamp': 1641491880000, 'value': 78.5}
]

Turning results into a csv is then straightforward.

import csv
with open("results.csv", "w", encoding="utf-8", newline="") as file_out:
    writer = csv.DictWriter(file_out, fieldnames=results[0].keys())
    writer.writeheader()
    writer.writerows(results)

giving a csv that looks like:

ID,timestamp,value
SERVICE-039D18D190DF8EE1,1641491760000,733
SERVICE-039D18D190DF8EE1,1641491820000,None
SERVICE-039D18D190DF8EE1,1641491880000,724
SERVICE-CF6C91BB030BB3AC,1641491760000,60951.354609929076
SERVICE-CF6C91BB030BB3AC,1641491820000,56788.070796460175
SERVICE-CF6C91BB030BB3AC,1641491880000,57866.69565217391
SERVICE-BF03689183860CA9,1641491760000,69
SERVICE-BF03689183860CA9,1641491820000,74
SERVICE-BF03689183860CA9,1641491880000,78.5
  •  Tags:  
  • Related