python api call using JSON data - python

Pretty new to Python API calls I Have the JSON data sample below
I can get data calling for example (swell.*) or (swell.minBreakingHeight) and it returns all the swell data no worries. So ok with a working request
I can't seem to narrow it down with success example swell.primary.height
Obviously the format above here is incorrect and keeps returning []
How do I get in that extra level?
[{
timestamp: 1366902000,
localTimestamp: 1366902000,
issueTimestamp: 1366848000,
fadedRating: 0,
solidRating: 0,
swell: {
minBreakingHeight: 1,
absMinBreakingHeight: 1.06,
maxBreakingHeight: 2,
absMaxBreakingHeight: 1.66,
unit: "ft",
components: {
combined: {
height: 1.1,
period: 14,
direction: 93.25,
compassDirection: "W"
},
primary: {
height: 1,
period: 7,
direction: 83.37,
compassDirection: "W"
},

Working with your data snippet:
data = [{
'timestamp': 1366902000,
'localTimestamp': 1366902000,
'issueTimestamp': 1366848000,
'fadedRating': 0,
'solidRating': 0,
'swell': {
'minBreakingHeight': 1,
'absMinBreakingHeight': 1.06,
'maxBreakingHeight': 2,
'absMaxBreakingHeight': 1.66,
'unit': "ft",
'components': {
'combined': {
'height': 1.1,
'period': 14,
'direction': 93.25,
'compassDirection': "W"
},
'primary': {
'height': 1,
'period': 7,
'direction': 83.37,
'compassDirection': "W"
}
}
}
}
]
In [54]: data[0]['timestamp']
Out[54]: 1366902000
In [55]: data[0]['swell']['components']['primary']['height']
Out[55]: 1
So using your dot notation, you should be calling:
swell.components.primary.height
For furhter insight on parsing json files refer to this other stackoverflow question

Related

python and Json - editing file

So, I want to change my info in json file from python, but I am having trouble.
my json file is just info that I want to edit later:
[
{
"codigo": 10,
"Nom_articulo": "jabon",
"valor": 2500,
"cantidad": 6,
"subtotal": 0,
"descuento": 0
},
{
"codigo": 20,
"Nom_articulo": "Crema",
"valor": 9800,
"cantidad": 4,
"subtotal": 0,
"descuento": 0
},
{
"codigo": 30,
"Nom_articulo": "Cepillo",
"valor": 6000,
"cantidad": 7,
"subtotal": 0,
"descuento": 0
},
{
"codigo": 40,
"Nom_articulo": "Servilletas",
"valor": 3000,
"cantidad": 2,
"subtotal": 0,
"descuento": 0
},
{
"codigo": 50,
"Nom_articulo": "Desodorante",
"valor": 5000,
"cantidad": 6,
"subtotal": 0,
"descuento": 0
}
]
I want to change the value of "subtotal" in all my dictionaries.
so basically what I did was:
for i in range(len(archivo_r)):
precio= archivo_r[i]["valor"]
cantidad=archivo_r[i]["cantidad"]
subtotal=precio*cantidad
print(archivo_r[i]["codigo"], " - " ,archivo_r[i]["Nom_articulo"], " = ", str(subtotal))
#almacenar mis subtotales en el archivo json
print("sbtotal" ,archivo_r[i]["subtotal"])
archivo_r[i]["subtotal"]=subtotal
#archivo_r[i]["subtotal"].append(subtotal)
#print(archivo_r)
write_json(**XXXXX**)
This part of the code:
archivo_r[i]["subtotal"]=subtotal does exactly what I need, but (and this could be very silly, but I am a little lost here) I do not know how to use that to re-write my json file. I mean, I have the function to write it.
def write_json(info, nombre_archivo="productos.json"):
with open(nombre_archivo, "w") as p:
json.dump(info, p)
I need to pass the information in write_json(**XXXXX**), but have been trying to storage my archivo_r[i]["subtotal"]=subtotal in a variable to pass it and other things, but nothing work. I know I am doing wrong but not sure how to solve it.
Once you're done processing the data, simply pass archivo_r to your write_json() function and you should be fine.
As an aside, you can iterate directly over the JSON objects like so:
for section in archivo_r:
precio = section["valor"]
...
You can then replace all instances of archivo_r[i] with section, or whatever you want to call the variable.

Bucketing for histogram in MongoDB

Syntax issue on line #25. Can someone please help me to spot the mistake not sure if the problem is in the code before this line.
File SyntaxError: invalid syntax, line 25
} #25
^
The line with the syntax is highlighted by #25. Thank you in advance :)
import pandas as pd
def length_vs_references(articles):
res = {"1-5" : 0, "6-10" : 0, "11-15" : 0, "16-20" : 0, "21-25" : 0, "25-30" : 0, ">30" :0}
n = {"1-5" : 0, "6-10" : 0, "11-15" : 0, "16-20" : 0, "21-25" : 0, "25-30" : 0, ">30" :0}
cursor = articles.aggregate([
{'$match': {'$and' : [{'references': {'$exists': False}
}, {'$ne':['$page_end', '']}, {'$ne':['$page_start', '']} ]}},
{'$project': {'len_refernces': {"$size": '$references'},
'pages': {'$subtract': [{"$toInt": 'page_end'},
{"$toInt" : 'page_start'}]}}},
{'$bucket' : {
'$groupBy': '$pages',
'boundaries': [ 0, 6, 11, 16, 21, 26, 31, 1000000],
'default': 'Other',
{
'output' : {"average": {"$avg" : '$len_references'}},
}
} #25
}
])
return cursor
print(length_vs_references(articles))
'default': 'Other',
{
'output' : {"average": {"$avg" : '$len_references'}},
}
That is the problem area. You have a sub-dictionary without a key name.
To illustrate the problem more simply, here is an equivalent dictionary:
mydict = {
'some_key': 5,
'other_key': 10,
'yet_another_key': 100,
3,
'final_key': 1000
}
The 3 is an error because it's just a value without a key name. Your code has a sub-dictionary instead of an integer, but it's the same kind of error.

Mongodb 4.2 update with aggregation pipeline faster method to update only one element in array?

I want to optimize this code since it is not so fast by design.
I have position with array scores for judges objects each have judge_id and evaluation. I want to update exactly one evaluation for judge_id == 1 and keep the rest unchanged in the fastest way in MongoDB. Extra requirement is to use update with aggregation pipeline (update=[...] not update={...} MongoDB 4.2).
First I scan the whole array to search matching element and update it (exactly one) than I search the whole array to search not matching elements. Can I for example find a matching element index and change only this element?
Maybe it is not possible in MongoDB to optimize it?
I want to use only update with aggregate pipeline - not classic syntax to define more complex conditional updated than is possible by classic syntax?
.update(filter={...}, update=[...]) I mean as update with aggregate pipeline not .update(filter={...}, update={...]).
Can you help with this problem?
import pymongo
client = pymongo.MongoClient()
client.drop_database('delete_it')
db = client.delete_it
db.position.create_index('position', unique=True)
position: pymongo.collection.Collection = db.position
def show_position():
r = position.find_one(
filter={'position': 1},
projection={'_id': False}
)
print(r)
def create_position():
position.delete_one(
filter={'position': 1}
)
position.insert_one(
document={'position': 1,
'scores': [{'judge_id': 1, 'evaluation': 3},
{'judge_id': 2, 'evaluation': 4},
{'judge_id': 3, 'evaluation': 5}]}
)
print('Original data:')
show_position()
def show_updated_position():
print('Updated data:')
show_position()
create_position()
position.update_one(
filter={'position': 1,
'scores.judge_id': 1},
update=[
{
'$set': {
'scores': {
'$concatArrays': [
{
# change evaluation of one element
'$map': {
# array with one element only matching
'input': {
'$filter': {
'input': '$scores',
'cond': {'$eq': ['$$this.judge_id', 1]}
}
},
'in': {
'$mergeObjects' : [
'$$this', {'evaluation': 10}
]
}
}
},
# array of rest elements not matching
{
'$filter': {
'input': '$scores',
'cond': {'$ne': ['$$this.judge_id', 1]}
}
}
]
}
}
}
],
)
show_updated_position()
I meanwhile I found that slower code is faster by timeit() see here - why map is faster then filter I do not know but it is faster:
I have such results now:
update_pipeline_concat_arrays 1.455e+00 1.000 3.843
update_find_and_replace 7.461e-01 0.513 1.971
update_pipeline_merge_objects 4.845e-01 0.333 1.280
update_find_one_and_update 3.798e-01 0.261 1.003
update_one 3.786e-01 0.260 1.000
Here is new the best code (you can replace previous function in full code) - strange I think that map is slower - still slower than update() or find() and replace():
position.update_one(
filter={'position': 1,
'scores.judge_id': 1},
update=[
{
'$set': {
'scores': {
'$map': {
'input': '$scores',
'in': {
'$mergeObjects': [
'$$this', {
'evaluation': {
'$cond': {
'if': {'$eq': ['$$this.judge_id', 1]},
'then': NEW_EVALUATION,
'else': '$$this.evaluation'
}
}
}
]
}
}
}
}
}
],
)

update array in mongodb with new item and value

I am trying to update the array: ['media_details'] with a local image path after the image has been downloaded. However using $push just added the local_url on top.
This is what ['media_details'] looks like:
"image_details": [
{
"processed": true,
"position": 0,
"seconds": "46",
"src_url": "https://xxxxx/1.jpg",
"image_fname": "1.jpg",
},
{
"processed": true,
"position": 1,
"seconds": "55",
"src_url": "https://xxxxx/2.jpg",
"image_fname": "2.jpg",
},
my code then downloads the image from the src_url and I want to add the local image url to the ['media_details'].
job = mongo.db.JobProcess
job.update({'_id': db_id},
{'$push': {
'image_details': {
'local_url': img_local_file,
}
}})
This adds the local_url to the top of the ['media_details'] - like so:
{'local_url': '/bin/static/5432ec0f-ea53-4fe1-83e4-f78166d1b9a6/1.jpg'},
{'local_url': '/bin/static/5432ec0f-ea53-4fe1-83e4-f78166d1b9a6/2.jpg'},
{'processed': True, 'position': 0, 'seconds': '46', 'src_url': 'https://xxxxx1.jpg', 'image_fname': '1.jpg'}
what I want it to do is:
"image_details": [
{
"processed": true,
"position": 0,
"seconds": "46",
"src_url": "https://xxxxx/1.jpg",
"image_fname": "1.jpg",
"local_url": "/bin/static/5432ec0f-ea53-4fe1-83e4-f78166d1b9a6/1.jpg"
},
but which command ($set, $push, $addToSet) is best suited for updating this? and how do I implement it?
You need to update the image_details array item using the positional operator $. You will need a query that can uniquely identify the array item, perhaps src_url:
job.update({$and:[
{"_id": db_id},
{"image_details.src_url": img_src_url }
]},
{$set :{"image_details.$.local_url": img_local_file },
{multi:false})
You need to use positional update operator
job.updateOne({
'_id': db_id,
'image_details.src_url': yourUrl,
}, {
$set: {
'image_details.$.local_url': img_local_file
});

Google Sheets alternating colors via API

Using the sheets API with Python I'm attempting to format a sheet using alternating colors. In the UI this is found at Format > Alternating colors...
From what I've been able to find this is done via the API using banding. Unfortunately, I haven't been able to find a working example of how this is done. Below is the values dictionary I've constructed, color values aren't important at the moment, I'd just like it to colorize the sheet.
requests = {
'bandedRange': {
'bandedRangeId': 1,
'range': {
'sheetId': 0,
'startRowIndex': 0,
'endRowIndex': len(values),
'startColumnIndex': 0,
'endColumnIndex': 4,
},
'rowProperties': {
'headerColor': {
'red': 1,
'green': 0,
'blue': 1,
'alpha': 1,
},
'firstBandColor': {
'red': 1,
'green': 0,
'blue': 0,
'alpha': 0,
},
'secondBandColor': {
'red': 0,
'green': 1,
'blue': 0,
'alpha': 0,
}
},
},
'fields': '*',
}
body = {'requests': requests}
response = service.spreadsheets().batchUpdate(spreadsheetId=spreadsheet_id, body=body).execute()
This fails with the following error:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python2.7/dist-packages/oauth2client/_helpers.py", line 133, in positional_wrapper
return wrapped(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/googleapiclient/http.py", line 840, in execute
raise HttpError(resp, content, uri=self.uri)
googleapiclient.errors.HttpError: <HttpError 400 when requesting https://sheets.googleapis.com/v4/spreadsheets/$spreadsheet_id:batchUpdate?alt=json returned "Invalid JSON payload received. Unknown name "banded_range" at 'requests': Cannot find field.">
I'm fairly certain my issue is the fields value, but I can't find a valid example of what to use here. I get the same error if I omit the fields key entirely.
Per the reference docs for batchUpdate, requests takes an array of Request objects. Each Request must have exactly one field set, the available fields for banding being:
"updateBanding": {
object(UpdateBandingRequest)
},
"addBanding": {
object(AddBandingRequest)
},
"deleteBanding": {
object(DeleteBandingRequest)
},
There is no field bandedRange, which is what you're trying to set. That's what the error message (Unknown name "banded_range" at 'requests': Cannot find field.) is saying... though I have no idea why it translated bandedRange to snake_case.
Depending on if you want to add or update the banded range, you'd set either updateBanding with an UpdateBandingRequest object, or addBanding with an AddBandingRequest object.
By adding addBanding to your JSON format. As explained above you will end up creating the below JSON. Also, the key fields is optional.
{'addBanding': {
'bandedRange': {
'bandedRangeId': 1,
'range': {
'sheetId': 0,
'startRowIndex': 0,
'endRowIndex': len(values),
'startColumnIndex': 0,
'endColumnIndex': 4,
},
'rowProperties': {
'headerColor': {
'red': 1,
'green': 0,
'blue': 1,
'alpha': 1,
},
'firstBandColor': {
'red': 1,
'green': 0,
'blue': 0,
'alpha': 0,
},
'secondBandColor': {
'red': 0,
'green': 1,
'blue': 0,
'alpha': 0,
}
},
},
},
},

Categories

Resources