How to find object in python list by attribute - python-3.x

If I have a list created like this:
list = [
{
"id": 1,
"name": "something 1"
},
{
"id": 2,
"name": "something 2"
}
]
and I want to grab information from one of the list items, using the id from the url like this:
#route.app('item/<int:id>')
def item(id):
name = ???
return render_template('index.html', name=name)
how would I get the name of the object in the list with the specific id from the url?

A simple for loop will do your work:
#route.app('item/<int:id>')
def item(id):
some_list = [
{
"id": 1,
"name": "something 1"
},
{
"id": 2,
"name": "something 2"
}
]
name = ""
for obj in some_list:
if obj['id'] == id:
name = obj['name']
return render_template('index.html', name=name)

Related

Groovy: Compare a response with a json file while ignoring certain keys

I have a response from a REST API with ~40k lines and I need to verify if the values in it match those in an already existing local file. The response does have a certain element which is dynamic and is based on the date and time the response has been received.
I need to compare the response with the local json file and make sure the values match, while ignoring that specific date&time element that comes through.
This is a snippet example of the response/json file:
[
{
"code" : "SJM",
"valuesCount" : [
{
"code" : "SJM",
"description" : "LAST_NAME FIRST_NAME-SJM (LMM/null)",
"period" : "November 2020",
"printedOn" : "31/01/2022 09:39:39",
"name" : "null",
"logo" : { },
"standardId" : true,
"dailyValues" : [
{
"index" : "odd",
"day" : "01",
"description" : "",
"time" : "23:59",
"cms" : "",
"hcv" : "",
"nm" : "",
"hcp" : "",
"hcz" : "",
"synDc" : "",
"jiJnm" : "",
"c1" : "",
"c2" : "",
"proHvs" : "",
"dcd" : "",
"dcs" : "",
"d1" : "",
"d2" : "",
"nbdays" : ""
},
]
}
}
]
]
The file contains hundreds of code entries, each with their own valuesCount maps, in which the the printedOn element appears and that's what I'm trying to ignore.
I've been trying to do this in Groovy and the only thing I've managed to find in the groovy docs is the removeAll() method thinking I could perhaps remove that key:value entirely but I don't think I'm using it right.
import groovy.json.*
def groovyUtils = new com.eviware.soapui.support.GroovyUtils(context)
def projectDir = groovyUtils.projectPath
def response = new JsonSlurper().parseText(context.expand( '${Request#Response}' ))
File jsonFile = new File(projectDir, "/Project/Resources/jsonFile.json")
def defaultValues = new JsonSlurper().parse(jsonFile)
var1 = response.removeAll{"printedOn"}
var2 = defaultValues.removeAll{"printedOn"}
if (var1 == var2) {
log.info "The request matches the default values."
} else {
throw new Exception("The request does not match the default values.");
}
This just returns a true statement for both cases.
Could anyone point me in the right direction?
Much appreciated.
You need to traverse into the hierarchy of lists/maps to alter the inner map and remove the printedOn key/value pair.
Also your json is broken with missing/extra brackets.
The following code:
import groovy.json.*
def data1 = '''\
[
{
"code": "SJM",
"valuesCount": [
{
"code": "SJM",
"description": "LAST_NAME FIRST_NAME-SJM (LMM/null)",
"period": "November 2020",
"printedOn": "31/01/2022 09:39:39",
"name": "null",
"logo": {},
"standardId": true,
"dailyValues": [
{
"index": "odd",
"day": "01",
"description": "",
"time": "23:59",
"cms": "",
"hcv": "",
"nm": "",
"hcp": "",
"hcz": "",
"synDc": "",
"jiJnm": "",
"c1": "",
"c2": "",
"proHvs": "",
"dcd": "",
"dcs": "",
"d1": "",
"d2": "",
"nbdays": ""
}
]
}
]
}
]'''
def data2 = '''\
[
{
"code": "SJM",
"valuesCount": [
{
"code": "SJM",
"description": "LAST_NAME FIRST_NAME-SJM (LMM/null)",
"period": "November 2020",
"printedOn": "25/11/2021 09:39:39",
"name": "null",
"logo": {},
"standardId": true,
"dailyValues": [
{
"index": "odd",
"day": "01",
"description": "",
"time": "23:59",
"cms": "",
"hcv": "",
"nm": "",
"hcp": "",
"hcz": "",
"synDc": "",
"jiJnm": "",
"c1": "",
"c2": "",
"proHvs": "",
"dcd": "",
"dcs": "",
"d1": "",
"d2": "",
"nbdays": ""
}
]
}
]
}
]'''
def parser = new JsonSlurper()
def json1 = parser.parseText(data1)
def json2 = parser.parseText(data2)
def clean1 = removeNoise(json1)
def clean2 = removeNoise(json2)
def out1 = JsonOutput.toJson(clean1)
def out2 = JsonOutput.toJson(clean2)
assert out1 == out2
if(out1 == out2) println "the two documents are identical"
else println "the two documents differ"
def removeNoise(json) {
json.collect { codeMap ->
codeMap.valuesCount = codeMap.valuesCount.collect { valuesMap ->
valuesMap.remove('printedOn')
valuesMap
}
codeMap
}
}
will produce the following output when executed:
─➤ groovy solution.groovy
the two documents are identical
─➤
The json in the above code has been corrected to be parseable. I manually changed the string dates so that data1 and data2 differ on the printedOn property.
edit - it seems that you can actually just do:
assert clean1 == clean2
// or
if (clean1 == clean2) ...
for the comparison. Cuts out the extra serialization step to json but also leaves me feeling a tad uncomfortable with trusting groovy to do the right thing when comparing a nested data structure like this.
I would probably still go with the serialization.

Iterate over N nested list and dictionaries

I have the following structure of JSON/Dict.
[
{
"childrens": [
{
"childrens": [
{
"name": "somenam1"
}
],
"name": "B999"
}
],
"name": "11111"
},
{
"childrens": [
{
"childrens": [
{
"name": "somename2"
},
{
"name": "somename3"
}
],
"name": "B5555"
},
{
"childrens": [
{
"name": "somename4"
}
],
"name": "B2222"
}
],
"name": "2222"
}
]
I want to iterate over all dictionaries and list inside root list and create single string for each dictionary inside root list.
Output will look like this (two lines):
1111|B999|somename1
2222|B5555|somename2|somename3|B2222|somename4
Also this is just an example i can have N nested childrens.
Looks like a good candidate for recursion:
def flatten(child):
if not child:
return child
return [child['name']] + [name for c in child.get('childrens', []) for name in flatten(c)]
In []:
for child in data:
print('|'.join(flatten(child)))
Out[]:
11111|B999|somenam1
2222|B5555|somename2|somename3|B2222|somename4
Sure you can just pass add a level arg and return that:
def flatten(child, level=0):
if not child:
return child
return [level] + [l for c in child.get('childrens', []) for l in flatten(c, level+1)]
In []:
for child in data:
print('|'.join(str(level) for level in flatten(child)))
Out[]:
0|1|2
0|1|2|2|1|2
Here's a solution by recursion
data_json = '[{"childrens":[{"childrens":[{"name":"somenam1"}],"name":"B999"}],"name":"11111"},{"childrens":[{"childrens":[{"name":"somename2"},{"name":"somename3"}],"name":"B5555"},{"childrens":[{"name":"somename4"}],"name":"B2222"}],"name":"2222"}]'
data = json.loads(data_json)
def get_names(data_dict):
if ("childrens" in data_dict):
ret_dict = "|".join(map(get_names, data_dict["childrens"]))
return data_dict["name"] + "|" + ret_dict
else:
return data_dict["name"]
def get_all_name(data):
for i in data:
print(get_names(i))
get_all_name(data)

Convert Nested Json to a single Key Value Pair

I have a list of Keys :
Server
Date
Severity
process
message
If there is a key "events" in my Dictionary, I need to replace the key with "Message" and the value of "indicator-type" will become the value of the message
List1=[
{
"server": "10.10.0.123",
"date": 1561994754,
"severity": "INFO",
"process": "webapp",
"message": "server started."
},
{
"server": "10.10.0.202",
"date": 1561994757000,
"source": "jvm-x994a",
"events": [{
"indicator-type": "memory-low"
}]
},
{
"server": "10.10.0.202",
"date": 1561994773000,
"source": "jvm-x994a",
"events": [{
"indicator-type": "memory-low"
}
]
}
]
Expected output:
List1=[
{
"server": "10.10.0.123",
"date": 1561994754,
"severity": "INFO",
"process": "webapp",
"message": "server started."
},
{
"server": "10.10.0.202",
"date": 1561994757000,
"source": "jvm-x994a",
"message": "memory-low"
},
{
"server": "10.10.0.202",
"date": 1561994773000,
"source": "jvm-x994a",
"message": "memory-low"
}
]
}
]
So Far I have Tried :
In the below code I am trying to check for the "events" key and replacing it with the "message" key, but when I am printing it is not replacing they key-value
output = []
d={}
for x in a:
d['server']=x['server']
if (str(x['date']).isdigit() == True):
d['date'] =2
# datetime.datetime.fromtimestamp(x['date'] / 1000.0).strftime('%Y-%m-%d %H:%M:%S.%f')
if ("events" in x):
for i in (x['events']):
if (i['indicator-level'] == 3):
d['severity'] = "INFO"
if (i['indicator-level'] == 7):
d['severity'] = "WARN"
if (i['indicator-type'] != None):
d['message'] = i['indicator-type']
Clean out the dictionary first before moving on to the next step.
def handle_events_key(dict_):
"""
Adds a new 'message' key to 'dict_' based on 'events' key.
Returns a new dictionary without the 'events' key.
"""
if 'events' in dict_:
dict_['message'] = dict_['events'][0]['indicator-type']
return {key: value for key, value in dict_.items() if key != 'events'}
def events_key_to_message(list_):
return [handle_events_key(dict_) for dict_ in list_]
# Usage
# List1 = ...
# Cleaning out the dictionary.
ListUpdated = events_key_to_message(List1)
Try this. I have modified the events handling parts.
output = []
for item in List1:
d = {}
d['server'] = item['server']
if (str(item['date']).isdigit() == True):
d['date'] =2
# datetime.datetime.fromtimestamp(x['date'] / 1000.0).strftime('%Y-%m-%d %H:%M:%S.%f')
# get will give you None and not raise an exception if there is no events key.
if item.get('events') is not None:
for event in item['events']:
if event.get('indicator-level') == 3: d['severity'] = "INFO"
if event.get('indicator-level') == 7: d['severity'] = "WARN"
if event.get('indicator-type') is not None: d['message'] = event['indicator-type']
output.append(d)
print(output)
# [{'server': '10.10.0.123', 'date': 2}, {'server': '10.10.0.202', 'date': 2, 'message': 'memory-low'}, {'server': '10.10.0.202', 'date': 2, 'message': 'memory-low'}]

Create an object that has a key where the value is an array

Basically, I want to somehow create a JSON object from a Groovy object. The Groovy object has key value pairs, and one of the values is a Groovy Array:
import groovy.json.*
// Imagine "handler" gets called somehow and an event gets passed to it.
def handler(event) {
def capabilitiesList = event.device.capabilities.findAll { attr -> attr.name != null }
def json = new JsonBuilder({
id event.deviceId
displayName event.displayName
value event.value
})
}
log.debug capabilitiesList
log.debug json.toPrettyString()
At this point, json.toPrettyString() gives me this:
{
"id": "asdfl469934623sdglsi3aqaq",
"displayName": "Some Lightbulb",
"value": "on"
}
And capabilitiesList gives me this:
["Test 1", "Test 2", "Test 3"]
How can I add the capabilitiesList array to the Groovy object so it gets converted to JSON?
I can't seem to get anything to work; the only thing that does work is this:
// ...
def json = new JsonBuilder({
id event.deviceId
displayName event.displayName
value event.value
capabilitiesList "Test 1", "Test 2", "Test 3"
})
// ...
Which gives me this (correct) JSON output:
{
"id": "asdfl469934623sdglsi3aqaq",
"displayName": "Some Lightbulb",
"value": "on",
"capabilitiesList": ["Test 1", "Test 2", "Test 3"]
}
But that obviously isn't useful because it's hard coded. So I tried referencing the Array directly like this:
// ...
def capabilitiesList = event.device.capabilities.findAll { attr -> attr.name != null }
def json = new JsonBuilder({
id event.deviceId
displayName event.displayName
value event.value
capabilitiesList capabilitiesList
})
// ...
But that breaks the JsonBuilder somehow, and it doesn't output anything.
I'm probably doing something really silly here but I can't quite figure out how to get this done. First time with Groovy as well. Thanks for the help!
Using the builder DSL should work. For example:
List list = ['Test1', 'Test2', 'Test3']
def builder = new groovy.json.JsonBuilder()
builder {
id "asdfl469934623sdglsi3aqaq"
displayName "Some Lightbulb"
value "on"
capabilitiesList list
}
println builder.toPrettyString()
prints
{
"id": "asdfl469934623sdglsi3aqaq",
"displayName": "Some Lightbulb",
"value": "on",
"capabilitiesList": [
"Test1",
"Test2",
"Test3"
]
}

Aggregation in arangodb using AQL

I'm attempting a fairly basic task in arangodb, using the SUM() aggregate function.
Here is a working query which returns the right data (though not yet aggregated):
FOR m IN pkg_spp_RegMem
FILTER m.memberId == "40289"
COLLECT member = m.memberId INTO g
RETURN { "memberId" : member, "amount" : g[*].m[*].items }
This returns the following results:
[
{
"memberId": "40289",
"amount": [
[
{
"amount": 50,
"description": "some description"
}
],
[
{
"amount": 50,
"description": "some description"
},
{
"amount": 500,
"description": "some description"
},
{
"amount": 0,
"description": "some description"
}
],
[
{
"amount": 0,
"description": "some description"
},
]
]
}
]
I am using Collect to group the results because a given memberId may have multiple'RegMem' objects. As you can see from the query/results, each object has a list of smaller objects called 'items', with each item having an amount and a description.
I want to SUM() the amounts by member. However, adjusting the query like this does not work:
FOR m IN pkg_spp_RegMem
FILTER m.memberId == "40289"
COLLECT member = m.memberId INTO g
RETURN { "memberId" : member, "amount" : SUM(g[*].m[*].items[*].amount) }
It returns 0 because it apparently can't find a field in the expanded items list called amount.
Looking at the results I can sort of understand why: the results are being returned such that items is actually a list, of lists of objects with amount/description. But I don't understand how to reference or expand the un-named list correctly to return the amount field values for the SUM() function.
Ideally the query should return the memberId and total amount, one row per member such that I can remove the filter and execute for all members.
Many thanks in advance if you can help!
Martin
PS I've worked through the AQL tutorial on the arangodb website and checked out the manual but what would really help me is loads more example queries to look through. If anyone knows of a resource like that or wants to share some of their own, 'much obliged. Cheers!
Edited: Misread the question the first time. The first one can be seen in theedit history, as it also contains some hints:
I replicated your data by creating some documents in this format (and some with only one item):
{
"memberId": "40289",
"items": [
{
"amount": 50,
"description": "some description"
},
{
"amount": 500,
"description": "some description"
}
]
}
Based on some of those types of documents, your non-summarized query should indeed be looking like this:
FOR m IN pkg_spp_RegMem
FILTER m.memberId == "40289"
COLLECT member = m.memberId INTO g
RETURN { "memberId" : member, "amount" : g[*].m[*].items }
The data returned:
[
{
"memberId": "40289",
"amount": [
[
{
"amount": 50,
"description": "some description"
},
{
"amount": 0,
"description": "some description"
}
],
[
{
"amount": 50,
"description": "some description"
},
{
"amount": 0,
"description": "some description"
}
],
[
{
"amount": 50,
"description": "some description"
}
],
[
{
"amount": 50,
"description": "some description"
},
{
"amount": 500,
"description": "some description"
}
],
[
{
"amount": 0,
"description": "some description"
}
],
[
{
"amount": 50,
"description": "some description"
},
{
"amount": 500,
"description": "some description"
}
]
]
}
]
Based on the non summarized version, you need to loop through the items of the groups that have been generated by the collect function and do your SUM() there.
In order to be able to SUM the items you must FLATTEN() them into a single list, before summarizing them.
FOR m IN pkg_spp_RegMem
FILTER m.memberId == "40289"
COLLECT member = m.memberId INTO g
RETURN { "memberId" : member, "amount" : SUM(
FLATTEN(
(
FOR r in g[*].m[*].items
RETURN r[*].amount
)
)
)
}
This results in:
[
{
"memberId": "40289",
"amount": 1250
}
]

Resources