Python List to Nested Json - python

I am having the following problem.
class Inventory:
def __init__(self,project_no,country,category,product,count):
self.project_no = project_no
self.country = country
self.category = category
self.product = product
self.count = count
inventory_list = []
inventory_list.append(Inventory(1,'USA','Beverages','Milk',2))
inventory_list.append(Inventory(1,'USA','Beverages','Juice',5))
inventory_list.append(Inventory(1,'USA','Snacks','Potato Chips',2))
inventory_list.append(Inventory(1,'USA','Oils','Canola',5))
inventory_list.append(Inventory(1,'USA','Oils','Olive',8))
inventory_list.append(Inventory(1,'CAN','Beverages','Milk',7))
inventory_list.append(Inventory(1,'CAN','Beverages','Juice',8))
inventory_list.append(Inventory(1,'CAN','Snacks','Potato Chips',8))
inventory_list.append(Inventory(1,'CAN','Oils','Canola',3))
inventory_list.append(Inventory(1,'CAN','Oils','Olive',4))
{'Inventory': [{'Country': inv.country , 'Category' : [{inv.category : [{'Product' : inv.product}]}] } for inv in inventory_list]}
This code is giving me the following output.
{'Inventory': [{'Country': 'USA',
'Category': [{'Beverages': [{'Product': 'Milk'}]}]},
{'Country': 'USA', 'Category': [{'Beverages': [{'Product': 'Juice'}]}]},
{'Country': 'USA', 'Category': [{'Snacks': [{'Product': 'Potato Chips'}]}]},
{'Country': 'USA', 'Category': [{'Oils': [{'Product': 'Canola'}]}]},
{'Country': 'USA', 'Category': [{'Oils': [{'Product': 'Olive'}]}]},
{'Country': 'CAN', 'Category': [{'Beverages': [{'Product': 'Milk'}]}]},
{'Country': 'CAN', 'Category': [{'Beverages': [{'Product': 'Juice'}]}]},
{'Country': 'CAN', 'Category': [{'Snacks': [{'Product': 'Potato Chips'}]}]},
{'Country': 'CAN', 'Category': [{'Oils': [{'Product': 'Canola'}]}]},
{'Country': 'CAN', 'Category': [{'Oils': [{'Product': 'Olive'}]}]}]}
What I actually need is more like below.
{
"Inventory": [{
"country": "USA",
"category": [{
"Beverages": [{
"product": "Milk",
"count": 2
}, {
"product": "Juice",
"count": 5
}]
}, {
"Snacks": [{
"product": "Potato Chips",
"count": 2
}]
}, {
"Oils": [{
"product": "Canola",
"count": 5
}, {
"product": "Olive",
"count": 8
}]
}]
}, {
"country": "CAN",
"category": [{
"Beverages": [{
"product": "Milk",
"count": 7
}, {
"product": "Juice",
"count": 8
}]
}, {
"Snacks": [{
"product": "Potato Chips",
"count": 8
}]
}, {
"Oils": [{
"product": "Canola",
"count": 3
}, {
"product": "Olive",
"count": 4
}]
}]
}
]
}
How to do this?
I thought list comprehension is the way to go.
But I am having trouble beyond this point.
I thought this should be really easy for a python coder.
With my limited python I could only reach this far.
If anyone can help.

I would suggest you try serializing your Inventory class using the json module. However, it looks like you'll want to reorganize your data a bit. From what I can tell, you want to have an inventory that has a collection of countries which contain a set of products separated into categories.
First, let's define the Product class:
class Product(object):
def __init__(self, name, count):
self.product = name
self.count = count
Next, we can define the Country class as a container for a set Products, arranged in a dictionary using the category name as the key.
class Country(object):
def __init__(self, name):
self.name = name
self.categories = dict()
def add_product_to_category(self, category, product):
if category not in self.categories:
self.categories[category] = []
self.categories[category].append(product)
Then, we can re-define the Inventory class as a container for a set of Country objects.
class Inventory(object):
def __init__(self, project_no):
self.project_no = project_no
self.countries = []
Next, we can use simple methods to fill out our classes with the required data.
inv = Inventory(1)
us_set = Country('USA')
us_set.add_product_to_category('Beverages', Product('Milk', 2))
us_set.add_product_to_category('Beverages', Product('Juice', 5))
us_set.add_product_to_category('Snacks', Product('Potato Chips', 2))
us_set.add_product_to_category('Oils', Product('Canola', 5))
us_set.add_product_to_category('Oils', Product('Olive', 8))
canada_set = Country('CAN')
canada_set.add_product_to_category('Beverages', Product('Milk', 7))
canada_set.add_product_to_category('Beverages', Product('Juice', 8))
canada_set.add_product_to_category('Snacks', Product('Potato Chips', 8))
canada_set.add_product_to_category('Oils', Product('Canola', 3))
canada_set.add_product_to_category('Oils', Product('Olive', 4))
inv.countries.append(us_set)
inv.countries.append(canada_set)
Finally, (to actually answer your question, lul) to serialize the Inventory class, we have to define an encoder to use:
class MyEncoder(json.JSONEncoder):
def default(self, o):
return o.__dict__
Now, we can just call json.dumps() to get a string output of our serialized Inventory.
json.dumps(inv, indent=2, cls=MyEncoder)
The output isn't exactly what you laid out, but I think this method will work well for you.
{
"project_no": 1,
"countries": [
{
"name": "USA",
"categories": {
"Beverages": [
{
"count": 2,
"product": "Milk"
},
{
"count": 5,
"product": "Juice"
}
],
"Oils": [
{
"count": 5,
"product": "Canola"
},
{
"count": 8,
"product": "Olive"
}
],
"Snacks": [
{
"count": 2,
"product": "Potato Chips"
}
]
}
},
{
"name": "CAN",
"categories": {
"Beverages": [
{
"count": 7,
"product": "Milk"
},
{
"count": 8,
"product": "Juice"
}
],
"Oils": [
{
"count": 3,
"product": "Canola"
},
{
"count": 4,
"product": "Olive"
}
],
"Snacks": [
{
"count": 8,
"product": "Potato Chips"
}
]
}
}
]
}

try using the json module, e.g.
import json
...
inv_json = {'Inventory': [{'Country': inv.country , 'Category' : [{inv.category : [{'Product' : inv.product}]}] } for inv in inventory_list]}
json_formatted_str = json.dumps(x, indent=2)
print(json_formatted_str)
https://www.journaldev.com/33302/python-pretty-print-json

Related

Django MPTT Queryset to nested dictionary without recursive calling

The Django MPPT is smart library that make only single query to get all nested data.
Is there a way to get the data as nested dictionary without recursive calling.
queryset = MyTreeModel.objects.values()
results = get_nested_dict(queryset) ???
results >>
{
'id': 7,
'name': 'parent',
'children': [
{
'id': 8,
'parent_id': 7,
'name': 'child',
'children': [
{
'id': 9,
'parent_id': 8,
'name': 'grandchild',
}
]
}
]
}
How to create get_nested_dict() without recursive calling?
My category hierarchy
from .models import Category
from mptt.utils import get_cached_trees
categories_list = Category.objects.all().order_by('name')
def get_nested_dictionary(queryset):
roots = get_cached_trees(queryset)
def form_a_tree(objects):
tree = []
for obj in objects:
children = obj.get_children()
dictionary_category_tree = {'id': obj.id, 'name': obj.name}
if children:
dictionary_category_tree.update({'children': form_a_tree(children)})
tree.append(dictionary_category_tree)
return tree
return form_a_tree(roots)
Result:
[
{
"id": 9,
"name": "C++",
"children": [
{
"id": 10,
"name": "C++ for beginners"
}
]
},
{
"id": 5,
"name": "JS",
"children": [
{
"id": 7,
"name": "JS for beginners"
}
]
},
{
"id": 1,
"name": "Python",
"children": [
{
"id": 2,
"name": "Python for beginners",
"children": [
{
"id": 4,
"name": "some subcategory"
},
{
"id": 6,
"name": "some subcategory2"
}
]
}
]
}
]
My solution makes only one query to db
Proof1
Proof2

How to add key value pair to dictionary which is present inside list

dict_example = {
"abc": [
{
"name": "bcd",
"gender": "male",
"options": {
"emp_id": "a10734",
"address": "cfg",
"dept": "IT",
},
}
]
}
I have above dictionary and I need to add below values to options programmatically.
"desgn":"Engineer",
"project" : "xyz",
I need output in the below formart
dict_example = {
"abc": [
{
"name": "bcd",
"gender": "male",
"options": {
"emp_id": "a10734",
"address": "cfg",
"dept": "IT",
"desgn":"Engineer",
"project" : "xyz",
},
}
]
}
Can anyone help me with the above problem it will be great!
You can simply use the keys and indices to reach the item and add or change it:
dict_example['abc'][0]['options']['design'] = 'Engineer'
dict_example['abc'][0]['options']['project'] = 'xyz'
print(dict_example)
The output will be:
{'abc': [{'name': 'bcd', 'gender': 'male', 'options': {'emp_id': 'a10734', 'address': 'cfg', 'dept': 'IT', 'design': 'Engineer', 'project': 'xyz'}}]}

Fetch the Json for a particular key value

for an input json
[{
"Name": "John",
"Age": "23",
"Des": "SE"
},
{
"Name": "Rai",
"Age": "33",
"Des": "SSE"
},
{
"Name": "James",
"Age": "42",
"Des": "SE"
}
]
I want to filter out the json data where only "Des":"SE" is true
required output
[{
"Name": "John",
"Age": "23"
},
{
"Name": "James",
"Age": "42"
}
]
A list comprehension should do it:
out = [{'Name':d['Name'], 'Age':d['Age']} for d in lst if d['Des']=='SE']
Another way:
out = [d for d in lst if d.pop('Des')=='SE']
Output:
[{'Name': 'John', 'Age': '23'}, {'Name': 'James', 'Age': '42'}]
To make it more dynamic if each json has more elements:
import json
input_str = '[{"Name": "John", "Age": "23", "Des": "SE"}, {"Name": "Rai", "Age": "33", "Des": "SSE"}, {"Name": "James", "Age": "42", "Des": "SE"}]'
input_list = json.loads(input_str)
# If you already converted to a list of dicts, then you don't need the above
# Using pop here removes the key you are using to filter
output = [each for each in input_list if each.pop("Des") == "SE"]
using the json module, you can load a file using loads or a string using load. From there, it acts as a normal python list of dictionaries which you can iterate over and check the keys of. From there, you simply create a new list of dictionaries that match your desired pattern and remove the key you are no longer using. Example:
import json
jsonString = """[{
"Name": "John",
"Age": "23",
"Des": "SE"
},
{
"Name": "Rai",
"Age": "33",
"Des": "SSE"
},
{
"Name": "James",
"Age": "42",
"Des": "SE"
}
]"""
jsonList = json.loads(jsonString)
filteredList = []
def CheckDes(dataDict: dict):
if dataDict['Des'] == 'SE':
dataDict.pop('Des')
filteredList.append(dataDict)
print(jsonList)
"""
[
{
'Name': 'John',
'Age': '23',
'Des': 'SE'
},
{
'Name': 'Rai',
'Age': '33',
'Des': 'SSE'
},
{
'Name': 'James',
'Age': '42',
'Des': 'SE'
}
]"""
[CheckDes(dataDict) for dataDict in jsonList]
print(filteredList)
"""[
{
'Name': 'John',
'Age': '23'
},
{
'Name': 'James',
'Age': '42'
}
]
"""

Create nested dictionary using keypath in Python

There is a nested dictionary with multiple level of keys. The requirements are:
Create nested keys by using keypath if it doesn't exist
Update the value by using the keypath if it exists
For example, this is the dictionary:
{
"animal": {
"dog": {
"type": "beagle"
}
},
"man": {
"name": "john",
"age": 36
},
"plant": {
"fruit": {
"apple": {
"type": "gala"
}
}
}
}
Here are the functions to update the value or append a new nested keypath:
appendDict(["man", "name"], "daniel", json_dict)
appendDict(["computer", "laptop", "maker"], "hp", json_dict)
Here is the expected result:
{
"animal": {
"dog": {
"type": "beagle"
}
},
"man": {
"name": "daniel",
"age": 36
},
"plant": {
"fruit": {
"apple": {
"type": "gala"
}
}
},
"computer": {
"laptop": {
"maker": "hp"
}
}
}
My question is how to implement the appendDict() function in order to support the requirements?
Here is my code so far which doesn't work yet:
json_dict = {
"animal": {"dog": {"type": "beagle"}},
"man": {"name": "john", "age": 36},
"plant": {"fruit": {"apple": {"type": "gala"}}}
}
def appendDict(keys, value, json_dict):
for index, key in enumerate(keys):
if key not in json_dict:
if index == len(keys) - 1:
some_data = {}
some_data[key] = value
json_dict[key] = some_data
else:
some_data = {}
json_dict[key] = some_data
else:
json_dict[key] = value
appendDict(["man", "name"], "daniel", json_dict)
appendDict(["computer", "laptop", "maker"], "hp", json_dict)
You can use recursion by slicing keys at every call:
def appendDict(keys, value, json_dict):
if len(keys) == 1:
json_dict[keys[0]] = value
else:
if keys[0] not in json_dict:
json_dict[keys[0]] = {}
appendDict(keys[1:], value, json_dict[keys[0]])
json_dict = {'animal': {'dog': {'type': 'beagle'}}, 'man': {'name': 'john', 'age': 36}, 'plant': {'fruit': {'apple': {'type': 'gala'}}}}
appendDict(["man", "name"], "daniel", json_dict)
appendDict(["computer", "laptop", "maker"], "hp", json_dict)
import json
print(json.dumps(json_dict, indent=4))
Output:
{
"animal": {
"dog": {
"type": "beagle"
}
},
"man": {
"name": "daniel",
"age": 36
},
"plant": {
"fruit": {
"apple": {
"type": "gala"
}
}
},
"computer": {
"laptop": {
"maker": "hp"
}
}
}

How to edit a value inside of a dictionary inside of array in MongoDB?

{
"_id": 1359185710985371235,
"main": 2,
"streamers": [{"name": "me", "count": 1},{"anothername", "count": 0}]
}
hey, I have a problem with mongodb and pymongo so basically i want to edit "count" inside of "streamers" . like i want to change count of "name": "me", "count": 1 to "name": "me", "count": 3How can i do it?
Please answer if you know MongoDB and also provide a console command on how to do it.
From mongo shell:
db.example.insertOne(
{
"_id": NumberLong("1359185710985371235"),
"main": 2,
"streamers": [ { "name": "me", "count": 1 },{ name: "anothername", "count": 0 } ]
} )
db.example.updateOne(
{ _id: NumberLong("1359185710985371235"), 'streamers.name': 'me' },
{ $set: { 'streamers.$[st].count' : 3 } },
{ arrayFilters: [ { 'st.name': 'me' } ] }
)
From Python shell using PyMongo:
db.example.update_one(
{ '_id': 1359185710985371235, 'streamers.name': 'me' },
{ '$set': { 'streamers.$[st].count' : 3 } },
array_filters = [ { 'st.name': 'me' } ]
)
Pymongo way to do it:
import pymongo
db = pymongo.MongoClient()['mydatabase']
# Data setup
db.mycollection.insert_one({"main": 2, "streamers": [{"name": "me", "count": 1},{"name": "anothername", "count": 0}]})
record = db.mycollection.find_one({"main": 2})
streamers = record.get('streamers')
for index, streamer in enumerate(streamers):
name = streamer.get('name')
if name == "me":
streamer['count'] = 3
streamers[index] = streamer
record = db.mycollection.update_one({"_id": record['_id']}, {'$set': {'streamers': streamers}})
print(db.mycollection.find_one({"main": 2}))
Output:
{'_id': ObjectId('5e904277152eaccd43dddf8d'), 'main': 2, 'streamers': [{'name': 'me', 'count': 3}, {'name': 'anothername', 'count': 0}]}

Categories

Resources