Unable to append data to array - python

I am retrieving a record set from a database.
Then using a for statement I am trying to construct my data to match a 3rd party API.
But I get this error and can't figure it out:
"errorType": "TypeError", "errorMessage": "list indices must be
integers, not str"
"messages['english']['merge_vars']['vars'].append({"
Below is my code:
cursor = connect_to_database()
records = get_records(cursor)
template = dict()
messages = dict()
template['english'] = "SOME_TEMPLATE reminder-to-user-english"
messages['english'] = {
'subject': "Reminder (#*|code|*)",
'from_email': 'mail#mail.com',
'from_name': 'Notifier',
'to': [],
'merge_vars': [],
'track_opens': True,
'track_clicks': True,
'important': True
}
for record in records:
record = dict(record)
if record['lang'] == 'english':
messages['english']['to'].append({
'email': record['email'],
'type': 'to'
})
messages['english']['merge_vars'].append({
'rcpt': record['email']
})
for (key, value) in record.iteritems():
messages['english']['merge_vars']['vars'].append({
'name': key,
'content': value
})
else:
template['other'] = "SOME_TEMPLATE reminder-to-user-other"
close_database_connection()
return messages
The goal is to get something like this below:
messages = {
'subject': "...",
'from_email': "...",
'from_name': "...",
'to': [
{
'email': '...',
'type': 'to',
},
{
'email': '...',
'type': 'to',
}
],
'merge_vars': [
{
'rcpt': '...',
'vars': [
{
'content': '...',
'name': '...'
},
{
'content': '...',
'name': '...'
}
]
},
{
'rcpt': '...',
'vars': [
{
'content': '...',
'name': '...'
},
{
'content': '...',
'name': '...'
}
]
}
]
}

This code seems to indicate that messages['english']['merge_vars'] is a list, since you initialize it as such:
messages['english'] = {
...
'merge_vars': [],
...
}
And call append on it:
messages['english']['merge_vars'].append({
'rcpt': record['email']
})
However later, you treat it as a dictionary when you call:
messages['english']['merge_vars']['vars']
It seems what you want is something more like:
vars = [{'name': key, 'content': value} for key, value in record.iteritems()]
messages['english']['merge_vars'].append({
'rcpt': record['email'],
'vars': vars,
})
Then, the for loop is unnecessary.

What the error is saying is that you are trying to access an array element with the help of string not index (int).
I believe your mistake is in this line:
messages['english']['merge_vars']['vars'].append({..})
You declared merge_vars as array like so:
'merge_vars': []
So, you either make it dict like this:
'merge_vars': {}
Or, use it as array:
messages['english']['merge_vars'].append({..})
Hope it helps

Your issues, as the Error Message is saying, is here: messages['english']['merge_vars']['vars'].append({'name': key,'content': value})
The item messages['english']['merge_vars'] is a list and thus you're trying to access an element when you do something like list[i] and i cannot be a string, as is the case with 'vars'. You probably either need to drop the ['vars'] part or set messages['english']['merge_vars'] to be a dict so that it allows for additional indexing.

Related

How to replace json value with list of items based on the key

How do I replace the json_object's blookup with blookup_values based on the ID's in the json blookup. I tried the below code by removing the ID's which are not present in the json_object['blookup']. The below code doesn't work. Could anyone please help.
blookup_values = [
{
"id":"123",
"name":"abc",
"date":"somedate",
"time":"sometime"
},
{
"id":"456",
"name":"def",
"date":"somedate",
"time":"sometime"
},
{
"id":"789",
"name":"ghi",
"date":"somedate",
"time":"sometime"
},
{
"id":"9999",
"name":"mmmmmm",
"date":"somedate",
"time":"sometime"
},
{
"id":"8888",
"name":"nnnnnn",
"date":"somedate",
"time":"sometime"
}
]
json_object = {
"id":"id_value",
"blookup": [{
"id":"123",
"type":"dddd"
},
{
"id":"456",
"type":"eeeee"
}
]
}
Code
result = [obj for obj in blookup_values if obj['id'] != json_object['blookup']]
Expected result
result = {
"id":"id_value",
"blookup": [{
"id":"123",
"name":"abc",
"date":"somedate",
"time":"sometime"
},
{
"id":"456",
"name":"def",
"date":"somedate",
"time":"sometime"
}
]
}
You have to get the id key from the json_object dictionaries:
result = [obj for obj in blookup_values if obj['id'] in [i["id"] for i in json_object['blookup']]]
First convert blookup_values into a dictionary keyed by id. Then you can replace json_object['blookup'] with a list comprehension made from this.
blookup_dict = {value['id']: value for value in blookup_values}
json_object['blookup'] = [blookup_dict[item['id']] for item in json_object['blookup']]
I’m not sure I completely understand what you are trying to do but what I gather is that you want to get the objects in blookup that do not have any of the same ids as the objects in json_objects. Is that correct?
Try to first get the id values of each object in json_object['blookup']. For example:
json_object_ids = [obj['id'] for obj in json_object['blookup']]
Next, filter the objects in blookup by slightly altering your list comprehension:
result = [obj for obj in blookup_values if obj['id'] not in json_object_ids]
The output would look something like this:
[{'id': '789', 'name': 'ghi', 'date': 'somedate', 'time':
'sometime'}, {'id': '9999', 'name': 'mmmmmm', 'date': 'som
edate', 'time': 'sometime'}, {'id': '8888', 'name': 'nnnnn
n', 'date': 'somedate', 'time': 'sometime'}]

Removing certain set of value within Python request text

I got this chunk from a response text after calling an API. How do I remove only the set with '"id": 23732 along with its other key:values ,' from the string?
{
"jobs": [
{
"id": 23732,
"status": "done",
"name": "TESTRBZ7664"
},
{
"id": 23730,
"status": "done",
"name": "RBY5434"
}
]
}
TQ
Convert the string to a json using json.loads() or response.json()
See the following code
In [4]: d
Out[4]:
{'jobs': [{'id': 23732, 'status': 'done', 'name': 'TESTRBZ7664'},
{'id': 23730, 'status': 'done', 'name': 'RBY5434'}]}
In [5]: [i for i in d["jobs"] if i["id"] != 23732]
Out[5]: [{'id': 23730, 'status': 'done', 'name': 'RBY5434'}]
Assuming the dict you posted is called original_dict, you could build a new dict using a list comprehension:
new_data = {
"jobs": [x for x in original_dict if x["id"] != 23732]
}
This doesn't strictly remove the entry from your original dict, it rather creates a new dict that doesn't contain the unwanted entry.
Read more about list comprehensions here: https://www.w3schools.com/python/python_lists_comprehension.asp

How do I get the value of a dict item within a list, within a dict?

How do I get the value of a dict item within a list, within a dict in Python? Please see the following code for an example of what I mean.
I use the following lines of code in Python to get data from an API.
res = requests.get('https://api.data.amsterdam.nl/bag/v1.1/nummeraanduiding/', params)
data = res.json()
data then returns the following Python dictionary:
{
'_links': {
'next': {
'href': null
},
'previous': {
"href": null
},
'self': {
'href': 'https://api.data.amsterdam.nl/bag/v1.1/nummeraanduiding/'
}
},
'count': 1,
'results': [
{
'_display': 'Maple Street 99',
'_links': {
'self': {
'href': 'https://api.data.amsterdam.nl/bag/v1.1/nummeraanduiding/XXXXXXXXXXXXXXXX/'
}
},
'dataset': 'bag',
'landelijk_id': 'XXXXXXXXXXXXXXXX',
'type_adres': 'Hoofdadres',
'vbo_status': 'Verblijfsobject in gebruik'
}
]
}
Using Python, how do I get the value for 'landelijk_id', represented by the twelve Xs?
This should work:
>>> data['results'][0]['landelijk_id']
"XXXXXXXXXXXXXXXX"
You can just chain those [] for each child you need to access.
I'd recommend using the jmespath package to make handling nested Dictionaries easier. https://pypi.org/project/jmespath/
import jmespath
import requests
res = requests.get('https://api.data.amsterdam.nl/bag/v1.1/nummeraanduiding/', params)
data = res.json()
print(jmespath.search('results[].landelijk_id', data)

MongoDB watch() aggregation match by field value

When I use the watch() function on my collection, I am passing a aggregation to filter what comes through. I was able to get operationType to work correctly, but I also only want to include documents in which the city field is equal to Vancouver. The current syntax I am using does not work:
change_stream = client.mydb.mycollection.watch([
{
'$match': {
'operationType': { '$in': ['replace', 'insert'] },
'fullDocument': {'city': {'$eq': 'Vancouver'} }
}
}
])
And for reference, this is the what the dictionary that I'm aggregating looks like:
{'_id': {'_data': '825F...E0004'},
'clusterTime': Timestamp(1595565179, 2),
'documentKey': {'_id': ObjectId('70fc7871...')},
'fullDocument': {'_id': ObjectId('70fc7871...'),
'city': 'Vancouver',
'ns': {'coll': 'notification', 'db': 'pipeline'},
'operationType': 'replace'}
I found I just have to use a dot to access the nested dictionary:
change_stream = client.mydb.mycollection.watch([
{
'$match': {
'operationType': { '$in': ['replace', 'insert'] },
'fullDocument.city': 'Vancouver' }
}
}
])

Regroup JSON file in a new format

I'm need a little help reordering this JSON data:
I've this file at this moment:
[{"aName":{"name":"somename","vendor":"vendor1"}},
{"bName":{"name":"somename","vendor":"vendor2"}},
{"cName":{"name":"othername","vendor":"vendor1"}
}]
I need re order it like this:
[{"name":"vendor1"},
{"child":[{"name":"somename","id":"aName"},
{"name":"othername","id":"cName"}]},
{"name":"vendor2"},
{"child":[{"name":"somename","id":"bName"}]}]
I was trying with this:
new format = []
for i in old_format:
new_format.setdefault(i['vendor'], []).append({"children":{"name":i['name'],"id":i}})
it's "closer", but not what I want
{
"vendor1":[
{
"children":{
"name":"somename",
"id":"aName"
}
},
{
"children":{
"name":"othername",
"id":"cName"
}
}
],
"vendor2":[
{
"children":{
"name":"somename",
"id":"bName"
}
}
]
}
I'll appreciate any advice.
The data representation you're using is a little strange... You have a lot of dictionaries with one entry, which suggests to me that you'd be better off rethinking how you store your data.
That said, this bit of code should do what you want:
vendors = {}
for entry in data:
for identifier, info in entry.items():
children = vendors.setdefault(info['vendor'], [])
children.append({
'name': info['name'],
'id': identifier
})
res = []
for vendor, children in vendors.items():
res.append({'name': vendor})
res.append({'child': children})
Here data is your input -- a list of dictionaries -- and res is the result:
[{'name': 'vendor2'},
{'child': [{'id': 'bName', 'name': 'somename'}]},
{'name': 'vendor1'},
{'child': [{'id': 'aName', 'name': 'somename'},
{'id': 'cName', 'name': 'othername'}]}]

Categories

Resources