Get keys of json data of certain level - json

I got parsed data object. The data is retuned by backend as JSON and has been parsed as data object in react-native client.
{
"level1-key1": "value1",
"level1-key2": "value2",
"level1-key3": "value3",
"level1-key4":{
"level2-k1": "val1",
"level2-k2": {
"level3-k1": "v1",
"level3-k2": "v2",
"level3-k3": "v3"
}
}
}
I would like to get different level keys as an array of strings, i.e. I want to get level 2 keys, which are ["level2-k1", "level2-k2"].
I want to get level 3 keys, which are
["level3-k1", "level3-k2", "level3-k3"]
How achieve it?

I think it should solve your problem
const data = {
'level1-key1': 'value1',
'level1-key2': 'value2',
'level1-key3': 'value3',
'level1-key4': {
'level2-k1': 'val1',
'level2-k2': {
'level3-k1': 'v1',
'level3-k2': 'v2',
'level3-k3': 'v3',
},
},
};
const isObject = (v) => typeof v === 'object' && v != null;
const getAllKeysByLevel = (data, level) => {
let levelObjects = [data];
for (let i = 0; i < level; i += 1) {
levelObjects = levelObjects.flatMap((item) =>
isObject(item) ? Object.values(item) : [],
);
}
return levelObjects.flatMap((item) =>
isObject(item) ? Object.keys(item) : [],
);
};
const level1 = getAllKeysByLevel(data, 0);
const level2 = getAllKeysByLevel(data, 1);
const level3 = getAllKeysByLevel(data, 2);
console.log(' --- xdebug ', {
level1,
level2,
level3,
});
/*
--- xdebug {
level1: [ 'level1-key1', 'level1-key2', 'level1-key3', 'level1-key4' ],
level2: [ 'level2-k1', 'level2-k2' ],
level3: [ 'level3-k1', 'level3-k2', 'level3-k3' ]
}
*/

This should do the work, finding out the leaf nodes and check if it is an object and repeat it till the end.
const data = {
"level1-key1": "value1",
"level1-key2": "value2",
"level1-key3": "value3",
"level1-key4":{
"level2-k1": "val1",
"level2-k2": {
"level3-k1": "v1",
"level3-k2": "v2",
"level3-k3": "v3"
}
}
}
function findLevels(data){
let counter = 1;
let final = {};
getKeys(data)
function getKeys(obj){
let k = Object.keys(obj);
final[counter] = k;
// scan if there is any object
for(let i = 0; i < k.length; i++){
if(typeof obj[k[i]] === "object"){
counter += 1;
getKeys(obj[k[i]])
}
}
}
return final;
}
const result = findLevels(data);
console.log(result)

Related

JSON data calculation and re-formate using Angular

I have a JSON file and I am trying to calculate the JSON file key based on the value and reformating it. My JSON file looks like below:
data=[
{
pet:'Cat',
fruit:'Apple',
fish:'Hilsha'
},
{
pet:'Dog',
fish:'Carp'
},
{
pet:'Cat',
fruit:'Orange',
fish:'Lobster'
}
];
I do like to calculate and formate it like below:
data=[
{
label:'Pet',
total:3,
list:[
{
name:'Cat',
value: 2,
},
{
name:'Dog',
value: 1,
}
]
},
{
label:'Fruit',
total:2,
list:[
{
name:'Apple',
value: 1,
},
{
name:'Orange',
value: 1,
}
]
},
{
label:'Fish',
total:3,
list:[
{
name:'Hilsha',
value: 1,
},
{
name:'Carp',
value: 1,
},
{
name:'Lobster',
value: 1,
}
]
},
];
If anybody can help me, it will be very help for me and will save a day.
I have fixed this task myself. If I have any wrong, you can put your comment fill-free :)
``
ngOnInit(): void {
this.dataService.$data.subscribe(data => {
// Create new object and calculation according to category
let petObj: any = {}
let fruitObj: any = {}
let fishObj: any = {}
data.forEach((el: any) => {
if (el.pet != undefined) {
petObj[el.pet] = (petObj[el.pet] || 0) + 1;
}
if (el.fruit != undefined) {
fruitObj[el.fruit] = (fruitObj[el.fruit] || 0) + 1;
}
if (el.fish != undefined) {
fishObj[el.fish] = (fishObj[el.fish] || 0) + 1;
}
});
// Create list according to category
let pet_list: any = [];
let fruit_list: any = [];
let fish_list: any = [];
for (var key in petObj) {
let pet = {
label: key,
value: petObj[key]
}
pet_list.push(pet)
}
for (var key in fruitObj) {
let fruit = {
label: key,
value: fruitObj[key]
}
fruit_list.push(fruit)
}
for (var key in fishObj) {
let fish = {
label: key,
value: fishObj[key]
}
fish_list.push(fish)
}
// Calculate total sum according to category
var totalPet = pet_list.map((res: any) => res.value).reduce((a: any, b: any) => a + b);
var totalFruit = fruit_list.map((res: any) => res.value).reduce((a: any, b: any) => a + b);
var totalFish = fish_list.map((res: any) => res.value).reduce((a: any, b: any) => a + b);
// Rearrange the JSON
this.rearrangeData = [
{
label: 'Pet',
total: totalPet,
list: pet_list
},
{
label: 'Fruit',
total: totalFruit,
list: fruit_list
},
{
label: 'Fish',
total: totalFish,
list: fish_list
}
]
console.log(this.rearrangeData)
// End rearrange the JSON
});
}
``
You can simplify your function. Take a look this one
group(oldData) {
const data = []; //declare an empty array
oldData.forEach((x) => {
//x will be {pet: 'Cat',fruit: 'Apple',fish: 'Hilsha'},
// {pet: 'Dog',fish: 'Carp'}
// ...
Object.keys(x).forEach((key) => {
//key will be 'pet','fruit',...
const item = data.find((d) => d.label == key); //search in the "data array"
if (item) { //if find it
item.total++; //add 1 to the property total of the element find it
// and search in the item.list the 'Cat'
const list = item.list.find((l) => l.name == x[key]);
//if find it add 1 to the property value of the list
if (list)
list.value++;
else
//if not, add to the list
//an object with property "name" and "value" equal 1
item.list.push({ name: x[key], value: 1 });
} else
//if the element is not in the "array data"
//add an object with properties label, total and list
//see that list is an array with an unique element
data.push({
label: key,
total: 1,
list: [{ name: x[key], value: 1 }],
});
});
});
return data;
}
You can use like
this.dataService.$data.subscribe(data => {
this.rearrangeData=this.group(data)
}
NOTE: this function the labels are 'pet','fruit' and 'fish' not 'Pet', 'Fruit' and 'Fish'
Did you try reading the text leading up to this exercise? That'd be my first approach. After that, I'd use reduce. You can do pretty much anything with reduce.

Unable to access inner JSON value in JSON array - Typescript(Using Angular 8)

I am trying to use the group by function on a JSON array using the inner JSON value as a key as shown below. But unable to read the inner JSON value. Here is my JSON array.
NotificationData = [
{
"eventId":"90989",
"eventTime":"2019-12-11T11:20:53+04:00",
"eventType":"yyyy",
"event":{
"ServiceOrder":{
"externalId":"2434",
"priority":"1"
}
}
},
{
"eventId":"6576",
"eventTime":"2019-12-11T11:20:53+04:00",
"eventType":"yyyy",
"event":{
"ServiceOrder":{
"externalId":"78657",
"priority":"1"
}
}
}
]
GroupBy Logic:
const groupBy = (array, key) => {
return array.reduce((result, currentValue) => {
(result[currentValue[key]] = result[currentValue[key]] || []).push(
currentValue
);
return result;
}, {});
};
const serviceOrdersGroupedByExternalId = groupBy(this.NotificationData, 'event.ServiceOrder.externalId');
//this line of code is not working as
// it is unable to locate the external id value.
Desired output
{ "2434":[{
"eventId":"90989",
"eventTime":"2019-12-11T11:20:53+04:00",
"eventType":"yyyy",
"event":{
"ServiceOrder":{ "priority":"1" }
}
}],
"78657":[{
"eventId":"6576",
"eventTime":"2019-12-11T11:20:53+04:00",
"eventType":"yyyy",
"event":{
"ServiceOrder":{ "priority":"1" }
}
}]
}
Does this solves your purpose?
let group = NotificationData.reduce((r, a) => {
let d = r[a.event.ServiceOrder.externalId] = [...r[a.event.ServiceOrder.externalId] || [], a];
return r;
}, {});
console.log(group);
Try like this:
result = {};
constructor() {
let externalIds = this.NotificationData.flatMap(item => item.event.ServiceOrder.externalId);
externalIds.forEach(id => {
var eventData = this.NotificationData.filter(
x => x.event.ServiceOrder.externalId == id
).map(function(item) {
delete item.event.ServiceOrder.externalId;
return item;
});
this.result[id] = eventData;
});
}
Working Demo

Node.js - JSON object manipulation

I have a problem converting my JSON to desired format. I have something like this:
{
"one:apple": "5",
"one:orange": "10",
"two:apple": "6",
"two:orange": "11"
}
and I would like to get:
[
["one","5","10"],
["two","6","11"]
]
Any help appreciated...
Assuming that your JSON is:
{
"one:apple": "5",
"one:orange": "10",
"two:apple": "6",
"two:orange": "11"
}
and your desired JSON is:
[
["one","5","10"],
["two","6","11"]
]
Then you can iterate over the keys of your object and add the values of the elements to another hash with shorter keys, and then convert that new hash to an array of arrays.
Example
let json1 = `{
"one:apple": "5",
"one:orange": "10",
"two:apple": "6",
"two:orange": "11"
}`;
function convert(j) {
let o = JSON.parse(j);
let h = {};
for (let k of Object.keys(o)) {
let n = k.split(':')[0];
if (!h[n]) h[n] = [];
h[n].push(o[k]);
}
let a = Object.keys(h).map(k => [k].concat(h[k]));
return JSON.stringify(a);
}
let json2 = convert(json1);
console.log('json1:', json1);
console.log('json2:', json2);
See: DEMO
Example for Node 0.10
This should work on Node v0.10.x:
var json1 = '{\n' +
' "one:apple": "5",\n' +
' "one:orange": "10",\n' +
' "two:apple": "6",\n' +
' "two:orange": "11"\n' +
'}';
function convert(j) {
var o = JSON.parse(j);
var h = {};
for (var k in o) {
if (o.hasOwnProperty(k)) {
var n = k.split(':')[0];
if (!h[n]) h[n] = [];
h[n].push(o[k]);
}
}
var a = Object.keys(h).map(function (k) {
return [k].concat(h[k]);
});
return JSON.stringify(a);
}
var json2 = convert(json1);
console.log('json1:', json1);
console.log('json2:', json2);
See: DEMO

How to find depth of nodes in a nested json file?

I found many solutions to find depth of nodes in a nested json file. but it throws me an error "maximum recursion depth exceeded "
when it set maximum recursion limit, it says "process exceeded with some error code"
As a part of my problem, I also need to find out key names of each node in the json file.
example json :
"attachments": {
"data": [
{
"media": {
"image": {
"height": 400,
"src": "https://scontent.xx.fbcdn.net/v/t1.0-1/10250217_10152130974757825_8645405213175562082_n.jpg?oh=904c1785fc974a3208f1d18ac07d59f3&oe=57CED94D",
"width": 400
}
},
"target": {
"id": "74286767824",
"url": "https://www.facebook.com/LAInternationalAirport/"
},
"title": "Los Angeles International Airport (LAX)",
"type": "map",
"url": "https://www.facebook.com/LAInternationalAirport/"
}
]
}
the output should be:
nodes:
[data [media [image[height,width,src]], target[id,url], title, type, url]]
depth: 4
If anyone else came here and found that the accepted answer does not work because Object.keys() for a string returns an array of each character of string and thus for either large objects or objects with large strings it just fails.
Here is something that works ->
function getDepth(obj){
if(!obj || obj.length===0 || typeof(obj)!=="object") return 0;
const keys = Object.keys(obj);
let depth = 0;
keys.forEach(key=>{
let tmpDepth = getDepth(obj[key]);
if(tmpDepth>depth){
depth = tmpDepth;
}
})
return depth+1;
}
Exmaple - https://jsfiddle.net/95g3ebp7/
Try the following function:
const getDepth = (
// eslint-disable-next-line #typescript-eslint/no-explicit-any
obj: Record<string, any>,
tempDepth?: number
): number => {
let depth = tempDepth ? tempDepth : 0;
if (obj !== null) {
depth++;
if (typeof obj === 'object' && !Array.isArray(obj)) {
const keys = Object.keys(obj);
if (keys.length > 0)
depth = Math.max(
...keys.map((key) => {
return getDepth(obj[key], depth);
})
);
} else if (Array.isArray(obj)) {
if (obj.length > 0)
depth = Math.max(
...obj.map((item) => {
return getDepth(item, depth);
})
);
}
}
return depth;
};
If you try this, I believe you have to get 7.
console.log(getDepth({
a: {
b: { a: [{ a: { a: [] } }] }
}
}));
function geth(obj) {
var depth = 0;
var k = Object.keys(obj);
console.log(k);
for (var i in k) {
var tmpDepth = geth(obj[k[i]]);
if (tmpDepth > depth) {
depth = tmpDepth
}
}
return 1 + depth;
}

mootools nested object filtering

I have a JSON string:
var data = {"categories":
[
{"id":1,"parent":0,"name":"Category A","description":"Category description","products":"11","subcategories":[]},
{"id":2,"parent":0,"name":"Category B","description":"Category description","products":"11","subcategories":
[
{"id":6,"parent":2,"name":"Subcategory F","description":"Category description", "products":"2","subcategories":[]},
{"id":7,"parent":2,"name":"Subcategory G","description":"Category description","products":"7","subcategories":[]}
]
},
{"id":3,"parent":0,"name":"Category C","description":"Category description","products":"4","subcategories":
[
{"id":8,"parent":3,"name":"Subcategory H","description":"Category description","products":"8","subcategories":[]}
]
},
{"id":4,"parent":0,"name":"Category D","description":"Category description","products":"45","subcategories":
[
{"id":9,"parent":4,"name":"Subcategory I","description":"Category description","products":"2","subcategories":
[
{"id":10,"parent":9,"name":"Subcategory J","description":"Category description","products":"54","subcategories":[]}
]
}
]
},{"id":5,"parent":0,"name":"Category E","description":"Category description","products":"89","subcategories":[]}
]
};
How can access to the data by id?
For example I need to get this sub_object with id = 10:
var requested = request(data, 10);
function request (data, id) {
var output = {};
...code
output = {"id":10,"parent":9,"name":"Subcategory J","description":"Category description","products":"54","subcategories":[]}
return output;
}
Basically you can do it by a simple recursion: http://jsfiddle.net/99UYU/
var data = {"categories":
[
{"id":1,"parent":0,"name":"Category A","description":"Category description","products":"11","subcategories":[]},
{"id":2,"parent":0,"name":"Category B","description":"Category description","products":"11","subcategories":
[
{"id":6,"parent":2,"name":"Subcategory F","description":"Category description", "products":"2","subcategories":[]},
{"id":7,"parent":2,"name":"Subcategory G","description":"Category description","products":"7","subcategories":[]}
]
},
{"id":3,"parent":0,"name":"Category C","description":"Category description","products":"4","subcategories":
[
{"id":8,"parent":3,"name":"Subcategory H","description":"Category description","products":"8","subcategories":[]}
]
},
{"id":4,"parent":0,"name":"Category D","description":"Category description","products":"45","subcategories":
[
{"id":9,"parent":4,"name":"Subcategory I","description":"Category description","products":"2","subcategories":
[
{"id":10,"parent":9,"name":"Subcategory J","description":"Category description","products":"54","subcategories":[]}
]
}
]
},{"id":5,"parent":0,"name":"Category E","description":"Category description","products":"89","subcategories":[]}
]
};
function recurseArr(arr,id){
for(var i=0;i<arr.length;i++){
var item = arr[i];
if(item.id == id){
return item;
}
var subcategories = item.subcategories;
var ret_val = recurseArr(subcategories,id);
if(ret_val){
return ret_val;
}
}
return null;
}
console.log(recurseArr(data.categories,10));
But you can save your data more usefully because you are using id anyhow - so instead array use objects(map):
var data = {"categories":
{
"1":{"parent":0,"name":"Category A","description":"Category description","products":"11","subcategories":{}},
"2":{"parent":0,"name":"Category B","description":"Category description","products":"11","subcategories":{
"6":{"parent":2,"name":"Subcategory F","description":"Category description", "products":"2","subcategories":{}},
"7":{"parent":2,"name":"Subcategory G","description":"Category description","products":"7","subcategories":{}}
}
}
}
};
then you can access your data more easily.