How to update a nested object inside DynamoDB? - python

I have an object on dynamo db saved in the following way:
{
"name": "nameA",
...,
"properties": {
"prop1": "a",
...
}
}
If I pass the following object:
{
"name": "nameUpdate"
}
I would like to eventually get the following result:
{
"name": "nameUpdate",
...,
"properties": {
"prop1": "a",
...
}
}
The problem is that I get the object without the nested field:
{
"name": "nameUpdate",
...,
"properties": {}
}
MY APPROACH
To perform the update operation I am proceeding as follows:
def build_ddb_update_expression(data):
prefix = '#pf'
vals = {}
exp = 'SET '
attr_names = {}
for key, value in data.items():
vals[f':{key}'] = value
attr_names[f'#pf_{key}'] = key
exp += f'{prefix}_{key} = :{key}, '
exp = exp.rstrip(", ")
return vals, exp, attr_names
...
vals, exp, attr_names = build_ddb_update_expression(
json.loads(json.dumps(object_to_update), parse_float=decimal.Decimal))
response = table.update_item(
Key={'object_id': object_id},
ConditionExpression='attribute_exists(object_id)',
UpdateExpression=exp,
ExpressionAttributeValues=vals,
ExpressionAttributeNames=attr_names,
ReturnValues="ALL_NEW"
)
Has this ever happened to anyone?
Thanks in advance

Related

python - collect full path till leaf on organization tree

I got organizations tree stored as json
{
"name": "amos",
"direct_reports": [
{
"name": "bart",
"direct_reports": [
{
"name": "colin",
"direct_reports": []
},
{
"name": "clara",
"direct_reports": []
}
]
},
{
"name": "bravo",
"direct_reports": [
{
"name": "cupid",
"direct_reports": []
},
{
"name": "clever",
"direct_reports": []
}
]
}
]
}
I need to store full "management path" for each employee, such as:
management_chain["clever"]={bravo,amos}
management_chain["bart"]={amos}
Currently I manage to reach all edges and classify those as employees and managers with code as followed:
def get_herarchy(org):
tmp_obj = {}
tmp_obj['managers'] = []
for emp in org['direct_reports']:
tmp_obj['managers'].append(org['name'])
print("manager "+org['name'])
if len(emp['direct_reports'])>0:
get_herarchy(emp)
tmp_obj['name'] = emp['name']
print(emp['name'])
return tmp_obj
But the dictionary doesn't holds the right values
Like this, maybe:
def get_chain(org, name):
if org['name'] == name:
return [name]
for emp in org['direct_reports']:
chain = get_chain(emp, name)
if chain:
return [org['name']] + chain
return None
print(get_chain(org, 'bart')) # ['amos', 'bart']
print(get_chain(org, 'clever')) # ['amos', 'bravo', 'clever']
UPD: This is how to make a dictionary:
def nested_iter(org):
yield org['name']
for emp in org['direct_reports']:
yield from nested_iter(emp)
print({name: get_chain(org, name)[0:-1] for name in nested_iter(org)})

How to access different keys within a json file?

I'm calling an API service which returns JSON (with Czech language values) that looks like:
{
"model": "czech-morfflex-pdt-161115",
"acknowledgements": [
"http://ufal.mff.cuni.cz/morphodita#morphodita_acknowledgements",
"http://ufal.mff.cuni.cz/morphodita/users-manual#czech-morfflex-pdt_acknowledgements"
],
"result": [
[
{
"token": "Děti",
"analyses": [
{
"lemma": "dítě",
"tag": "POS=N|SubPOS=N|Gen=F|Num=P|Cas=1|Neg=A"
},
{
"lemma": "dítě",
"tag": "POS=N|SubPOS=N|Gen=F|Num=P|Cas=4|Neg=A"
},
{
"lemma": "dítě",
"tag": "POS=N|SubPOS=N|Gen=F|Num=P|Cas=5|Neg=A"
}
],
"space": " "
},
...
I want to return "lemma" value where "tag" values Cas=3
I tried:
import json
import os
import httpx
service_url = "http://lindat.mff.cuni.cz/services/morphodita/api"
output_format = "json"
model = "czech-morfflex"
text = "Děti pojedou k babičce Martě. Už se těší."
anal_service_url = "/".join([service_url, "analyze"])
params = {"output": output_format, "model": model, "data": text}
response = httpx.request("GET", anal_service_url, params=params)
response.raise_for_status()
response_dict = response.json()
result = response_dict.get("result")
print(type(result))
for res in result:
for a in res:
for b in a['analyses']:
for case in b['tag'][4]:
for i in [i for i,x in enumerate(case) if x == '3']:
print(i) # print position
But I don't know how to access "lemma" if case=3.
Help would be appreciated.
You can use an if statement to find the tag in the string:
case_tag = 'Cas=3'
for res_list in result:
for res_list_elem in res_list:
for item in res_list_elem['analyses']:
if case_tag in item['tag']:
print(item['lemma'])

Python, JSON. How can I get a value from keys with the same name?

I need to grab "sid" value from my JSON
{
"response": [
{
"customName": "name-1",
"sid": "1247azc08belr2q4"
},
{
"customName": "name-2",
"sid": "zz63p2xxeh32b661"
},
{
"customName": "name-3",
"sid": "aa88p2xfeh32e661"
}
]
}
I tried to do
customName_1 = 'name-1'
customName_2 = 'name-2'
customName_3 = 'name-3'
for name in My_JSON['response']:
if name['customName'] == customName_3:
print(name['sid'])
else:
print('Cant get sid')
But it's not work because i grab "sid" from the first "customName" (name-1). Help me please with this.
You can use this snippet to return all 3 sid values....
MY_JSON = {
"response": [
{
"customName": "name-1",
"sid": "1247azc08belr2q4"
},
{
"customName": "name-2",
"sid": "zz63p2xxeh32b661"
},
{
"customName": "name-3",
"sid": "aa88p2xfeh32e661"
}
]
}
names = ["name-1", "name-2", "name-3"];
for name in MY_JSON['response']:
if name['customName'] in names:
print(name['sid'])
else:
print('Cant get sid')
This will store all the relevant 'sid'-values in the list sids. You could do this easily with json library as shown below.
Also, I used list comprehension to make your code more concise.
import json
d = json.loads(s)
sids = [customer['sid'] for customer in d['response'] if (customer['customName']=='name-3')]
print(sids)
Output:
['aa88p2xfeh32e661']
If you want sid values from all the customers, you could use the following piece of code.
sids = [customer['sid'] for customer in d['response']]
Dummy Data
s = """
{
"response": [
{
"customName": "name-1",
"sid": "1247azc08belr2q4"
},
{
"customName": "name-2",
"sid": "zz63p2xxeh32b661"
},
{
"customName": "name-3",
"sid": "aa88p2xfeh32e661"
}
]
}
"""
I sketched simple solution that might do what need.
def grab_item_by_attr(lst, attr_name, attr_value):
result = None
for item in lst:
if item[attr_name] == attr_value:
result = item
return result
When you call it, the result would be item you need:
>>> item = grab_item_by_attr(data['response'], 'customName', 'name-3')
>>> item
{'customName': 'name-3', 'sid': 'aa88p2xfeh32e661'}
>>> item['sid']
'aa88p2xfeh32e661'
I hope it helps!

Comparing Nested Python dict with list and dict

I've seen similar questions but none that exactly match what I'm doing and I believe other developers might face same issue if they are working with MongoDB.
I'm looking to compare two nested dict objects with dict and arrays and return a dict with additions and deletion (like you would git diff two files)
Here is what I have so far:
def dict_diff(alpha, beta, recurse_adds=False, recurse_dels=False):
"""
:return: differences between two python dict with adds and dels
example:
(This is the expected output)
{
'adds':
{
'specific_hours': [{'ends_at': '2015-12-25'}],
}
'dels':
{
'specific_hours': [{'ends_at': '2015-12-24'}],
'subscription_products': {'review_management': {'thiswillbedeleted': 'deleteme'}}
}
}
"""
if type(alpha) is dict and type(beta) is dict:
a_keys = alpha.keys()
b_keys = beta.keys()
dels = {}
adds = {}
for key in a_keys:
if type(alpha[key]) is list:
if alpha[key] != beta[key]:
adds[key] = dict_diff(alpha[key], beta[key], recurse_adds=True)
dels[key] = dict_diff(alpha[key], beta[key], recurse_dels=True)
elif type(alpha[key]) is dict:
if alpha[key] != beta[key]:
adds[key] = dict_diff(alpha[key], beta[key], recurse_adds=True)
dels[key] = dict_diff(alpha[key], beta[key], recurse_dels=True)
elif key not in b_keys:
dels[key] = alpha[key]
elif alpha[key] != beta[key]:
adds[key] = beta[key]
dels[key] = alpha[key]
for key in b_keys:
if key not in a_keys:
adds[key] = beta[key]
elif type(alpha) is list and type(beta) is list:
index = 0
adds=[]
dels=[]
for elem in alpha:
if alpha[index] != beta[index]:
dels.append(alpha[index])
adds.append(beta[index])
# print('update', adds, dels)
index+=1
else:
raise Exception("dict_diff function can only get dict objects")
if recurse_adds:
if bool(adds):
return adds
return {}
if recurse_dels:
if bool(dels):
return dels
return {}
return {'adds': adds, 'dels': dels}
The result I'm getting now is:
{'adds': {'specific_hours': [{'ends_at': '2015-12-24',
'open_hours': ['07:30-11:30', '12:30-21:30'],
'starts_at': '2015-12-22'},
{'ends_at': '2015-01-03',
'open_hours': ['07:30-11:30'],
'starts_at': '2015-01-0'}],
'subscription_products': {'review_management': {}}},
'dels': {'specific_hours': [{'ends_at': '2015-12-24',
'open_hours': ['07:30-11:30', '12:30-21:30'],
'starts_at': '2015-12-2'},
{'ends_at': '2015-01-03',
'open_hours': ['07:30-11:30'],
'starts_at': '2015-01-0'}],
'subscription_products': {'review_management': {'thiswillbedeleted': 'deleteme'}}}}
And this is the two objects I'm trying to compare:
alpha = {
'specific_hours': [
{
"starts_at": "2015-12-2",
"ends_at": "2015-12-24",
"open_hours": [
"07:30-11:30",
"12:30-21:30"
]
},
{
"starts_at": "2015-01-0",
"ends_at": "2015-01-03",
"open_hours": [
"07:30-11:30"
]
}
],
'subscription_products': {'presence_management':
{'expiration_date': 1953291600,
'payment_type': {
'free': 'iamfree',
'test': "test",
},
},
'review_management':
{'expiration_date': 1511799660,
'payment_type': {
'free': 'iamfree',
'test': "test",
},
'thiswillbedeleted': "deleteme",
}
},
}
beta = {
'specific_hours': [
{
"starts_at": "2015-12-22",
"ends_at": "2015-12-24",
"open_hours": [
"07:30-11:30",
"12:30-21:30"
]
},
{
"starts_at": "2015-01-0",
"ends_at": "2015-01-03",
"open_hours": [
"07:30-11:30"
]
}
],
'subscription_products': {'presence_management':
{'expiration_date': 1953291600,
'payment_type': {
'free': 'iamfree',
'test': "test",
},
},
'review_management':
{'expiration_date': 1511799660,
'payment_type': {
'free': 'iamfree',
'test': "test",
},
}
},
}

Python get a dict entry containing certain field

I have a nested dict in Python containing YAML structures like
- id: left_time
type: u2
doc: Time left
and I want to obtain pairs like {id: doc}. For this example I want it to be: {"left_time": "Time left"}. The problem is I need to walk through them recursively.
My attempt is
def get_dict_recursively(search_dict, field):
fields_found = []
name = ""
for key, value in search_dict.items():
if key == "id":
name = value
if key == field:
fields_found.append({name: value})
elif isinstance(value, dict):
results = get_dict_recursively(value, field)
for result in results:
fields_found.append({name: result})
elif isinstance(value, list):
for item in value:
if isinstance(item, dict):
more_results = get_dict_recursively(item, field)
for another_result in more_results:
fields_found.append({name: another_result})
return fields_found
calling it like
get_dict_recursively(dict, "doc")
where
dict = {
meta:
id: foo
title: Foo
types:
data:
seq:
- id: left_time
type: u2
doc: Time left
gps:
seq:
- id: gps_st
type: b2
- id: sats
type: b6
doc: Number of satellites
}
There's a mistake, but I can't find it out.
Let's first state your example data as a dict:
data = {
"meta": {
"id": "foo",
"title": "Foo"
},
"types": {
"data": {
"seq": [
{
"id": "left_time",
"type": "u2",
"doc": "Time left"
}
]
},
"gps": {
"seq": [
{
"id": "gps_st",
"type": "b2"
},
{
"id": "sats",
"type": "b6",
"doc": "Number of satellites"
}
]
}
}
}
Next, we can simplify your recursive function to look like this:
def extract_docs(data):
result = []
if isinstance(data, list):
for d in data:
result += extract_docs(d)
elif isinstance(data, dict):
if "id" in data and "doc" in data:
result.append((data["id"], data["doc"]))
else:
for d in data.values():
result += extract_docs(d)
return result
With this you get
>>> dict(extract_docs(data))
{'sats': 'Number of satellites', 'left_time': 'Time left'}

Categories