Creating custom json objects using changeable number of variables - javascript

I have this json object:
[
{
"trip": [
{
"place": {
"id": 8,
"name": "New York",
},
"group": 1
}
},
...
]
I can have a N number of groups, so i need to create an array of objects like this:
[
{
"group1": "New York",
"group2": "Los Angeles",
"group3": "Rome",
...
}
]
Each group is called groupX where X is a number taken from every "group" instance in every object in the first array and his value must be taken from "name" instance in every object in the first array.
How can i do it? Thanks in advance!

.map() is handy for getting an array of results, applying a function to each element of an existing array. Something like this:
var obj = [{
"trip": [{
"place": {
"id": 8,
"name": "New York",
},
"group": 1
}]
},
{
"trip": [{
"place": {
"id": 8,
"name": "london",
},
"group": 2
}]
},
{
"trip": [{
"place": {
"id": 8,
"name": "tokyo",
},
"group": 3
}]
},
]
var result = obj.map((array_element) => {
let group = "group" + String(array_element['trip'][0]['group'])
let place = String(array_element['trip'][0]['place']['name'])
let to_return = {};
to_return[group] = place
return to_return;
})
console.log(result)
/*
[
{ "group1": "New York" },
{ "group2": "london" },
{ "group3": "tokyo" }
]
*/

You can do it like this:
let data = [
{ 'trip': [{ 'place': { 'id': 8, 'name': 'New York' }, 'group': 1 }] },
{ 'trip': [{ 'place': { 'id': 9, 'name': 'Los Angeles' }, 'group': 2 }] },
{ 'trip': [{ 'place': { 'id': 10, 'name': 'Rome' }, 'group': 3 }] },
]
let grouped = data.reduce(function(grouped, current) {
grouped['group' + current.trip[0].group] = current.trip[0].place.name;
return grouped;
}, {})
console.log(grouped);

Related

How to filter from an object by iterating over it in js

I am trying to get the value of "type" from the object by iterating over it. The object looks like this.
{
"team": {
"table": [
{
"cityCode": 123,
"list": {
"players": [
{
"name": "peter",
"school": "x",
"awards": {
"type": "gold"
},
"year": 2019
}
]
}
},
{
"cityCode": 456,
"list": {
"players": [
{
"name": "Dave",
"school": "y",
"awards": {
"type": "silver"
},
"year": 2018
}
]
}
}
]
}
}
I am able to get the type values using this:
const table = team.table;
for (let i = 0; i < table.length; i++) {
const values = {
type: table[i].list.players
.filter((a) => a.awards != null)
.map((a) => a.awards.type)
.join(" "),
};
}
However, I want to use another filter on the "list" to filter non null lists. So how can I achieve that.
You want to check Check if 'list' key exists inside a team.table JSON object
you can check by
if(table[i].hasOwnProperty('list')){
}
code is
const table = team.table;
for (let i = 0; i < table.length; i++) {
if(table[i].hasOwnProperty('list')){
const values = {
type: table[i].list.players
.filter((a) => a.awards != null)
.map((a) => a.awards.type)
.join(" "),
};
}
}
1) You can get all type using flatMap and map as:
obj.team.table.flatMap((o) => o.list.players.map((o) => o.awards.type))
const obj = {
team: {
table: [
{
cityCode: 123,
list: {
players: [
{
name: "peter",
school: "x",
awards: {
type: "gold",
},
year: 2019,
},
],
},
},
{
cityCode: 456,
list: {
players: [
{
name: "Dave",
school: "y",
awards: {
type: "silver",
},
year: 2018,
},
],
},
},
],
},
};
const types = obj.team.table.flatMap((o) => o.list.players.map((o) => o.awards.type));
console.log(types);
2) Using forEach and destructuring as:
const obj = {
team: {
table: [
{
cityCode: 123,
list: {
players: [
{
name: "peter",
school: "x",
awards: {
type: "gold",
},
year: 2019,
},
],
},
},
{
cityCode: 456,
list: {
players: [
{
name: "Dave",
school: "y",
awards: {
type: "silver",
},
year: 2018,
},
],
},
},
],
},
};
const table = obj.team.table;
const types = [];
for (let i = 0; i < table.length; i++) {
const { list: { players } } = table[i]
players.forEach(({ awards: { type }}) => types.push(type))
}
console.log(types);
It will be cleaner to use forEach.
You will need 2 forEach due to your data structure.
But below code will:
check if awards is null
check if awards.type is null
const data = {
"team": {
"table": [
{
"cityCode": 123,
"list": {
"players": [
{
"name": "peter",
"school": "x",
"awards": {
"type": "gold"
},
"year": 2019
}
]
}
},
{
"cityCode": 456,
"list": {
"players": [
{
"name": "Dave",
"school": "y",
"awards": {
"type": "silver"
},
"year": 2018
},
{
"name": "Dave",
"school": "y",
"awards": {
"type": "gold"
},
"year": 2016
}
]
}
},
{
"cityCode": 444,
"list": {
"players": [
{
"name": "James",
"school": "y",
"awards": {
"type": null
},
"year": 2016
}
]
}
},
{
"cityCode": 555,
"list": {
"players": [
{
"name": "Name 101",
"school": "y",
"awards": {
"type": "platinum"
},
"year": 2016
},
{
"name": "Name 102",
"school": "y",
"awards": {
"type": null
},
"year": 2016
},
{
"name": "Name 103",
"school": "y",
"awards": null,
"year": 2016
},
]
}
}
]
}
}
// Expanded your data with more items
const data1 = data.team.table;
let types = []
data1.forEach((item, index) => {
item.list.players.forEach((player) => {
const awards = player.awards;
if (awards !== null && awards.type !== null) {
types = [...types, awards.type];
}
})
})
// Get the list of types
console.log(types);
// Get unique list of types
let unique_types = [...new Set(types)]
console.log(unique_types);

How to groupBy in multi arrays using lodash

I want to group By sub-work in array
Here is my array I want to group By sub-work
result = [
{
"date": "10-07-2019",
"data": [
{
"data_id": "20",
"work": "work_1",
"sub-work": "sub_work1",
"sub-data": [
{
"id": 7,
"title": 'subdata-1',
}
]
}
]
},
{
"date": "12-07-2019",
"data": [
{
"data_id": "20",
"work": "work_1",
"sub-work": "sub_work1",
"sub-data": [
{
"id": 7,
"title": 'subdata-1',
}
]
}
]
},
]
Here is what I try
result = _(result)
.map(function(items, data) {
_.groupBy(items.data, function({ sub_work }) {
return sub_work;
});
})
.value();
first I map result into data then I try to groupby but It's return null
Update
I want my output look like this
[
{
"date": "10-07-2019",
sub-work: [{
sub-work : "sub_work1",
sub-data[
{
"id": 7,
"title": 'subdata-1',
}
]
}]
}
]
...........................
It would be better if you could provide your expected result.
Here's what I could infer:
_(result)
.map(function(obj) { // Convert into a 2D array.
return obj.data.map(e => Object.assign(e, {date: obj.date}));
})
.flatten() // We have an array of objects now.
.groupBy('sub-work') // We can call groupBy().
.value();
Here's what you get:
{
"sub_work1": [{
"data_id": "20",
"work": "work_1",
"sub-work": "sub_work1",
"sub-data": [{
"id": 7,
"title": "subdata-1"
}],
"date": "10-07-2019"
}, {
"data_id": "20",
"work": "work_1",
"sub-work": "sub_work1",
"sub-data": [{
"id": 7,
"title": "subdata-1"
}],
"date": "12-07-2019"
}]
}

Find the parent of the searched value using javascript

I have a JSON data in the following format which needs to be filtered based on a specific value :
[
{
"id": 0,
"name": "ROOT-0",
"childs": [
{
"id": 1,
"name": "ROOT-1",
"childs": [
{
"id": 11,
"name": "ROOT-11",
},
{
"id": 12,
"name": "ROOT-12",
},
]
},
{
"id": 2,
"name": "ROOT-2",
"childs": [
{
"id": 21,
"name": "ROOT-21",
},
{
"id": 22,
"name": "ROOT-22",
},
]
},
{
"id": 3,
"name": "ROOT-3",
"childs": [
{
"id": 31,
"name": "ROOT-31",
},
{
"id": 32,
"name": "ROOT-32",
},
]
}
]
}]
The scenario is that I need to get ROOT-1 as final result if I look for ROOT-11/ROOT-12.
I have tried filtering with this following code
var res = data[0].filter(function f(o) {
if (o.name.includes("ROOT-11")) return o;
})
But I am not able to get a grip on the logic. Is there a way to achieve my desired output
You could use find()...
var result = data[0].childs.find(x => {
return x.childs.find(y => {
return y.name === name;
});
}).name;
Or you could write a function...
function findParentName(name, data) {
return data[0].childs.find(x => {
return x.childs.find(y => {
return y.name === name;
});
}).name;
}
var result = findParentName('ROOT-11', data);
console.log(result);
Doing this will give you the best performance result as find() will return as soon as it finds a match, and not iterate through each remaining loop like forEach() or map()
If you're using ES6 you can say...
const result = data[0].childs.find(x => x.childs.find(y => y.name === 'ROOT-11')).name;
You can grab the item using a few filters and a find, to get the result you are looking for:
let items = [{
"id": 0,
"name": "ROOT-0",
"childs": [{
"id": 1,
"name": "ROOT-1",
"childs": [{
"id": 11,
"name": "ROOT-11",
},
{
"id": 12,
"name": "ROOT-12",
},
]
},
{
"id": 2,
"name": "ROOT-2",
"childs": [{
"id": 21,
"name": "ROOT-21",
},
{
"id": 22,
"name": "ROOT-22",
},
]
},
{
"id": 3,
"name": "ROOT-3",
"childs": [{
"id": 31,
"name": "ROOT-31",
},
{
"id": 32,
"name": "ROOT-32",
},
]
}
]
}]
function find(name) {
let result
items.filter(item =>
result = item.childs.find(item2 =>
item2.childs.filter(i => i.name == name).length > 0
)
)
return result.name || ''
}
console.log(find('ROOT-11'))
console.log(find('ROOT-22'))
console.log(find('ROOT-32'))
You could, for an arbitrary count nested children, use a recusion approach by iterating the actual level and if not found check the children with the actual name.
If the wanted name is found, the parent's name is handed over through all nested calls and returned.
function getParent(array, search, parent) {
return array.some(o => o.name === search || o.children && (parent = getParent(o.children, search, o.name)))
&& parent;
}
var data = [{ id: 0, name: "ROOT-0", children: [{ id: 1, name: "ROOT-1", children: [{ id: 11, name: "ROOT-11" }, { id: 12, name: "ROOT-12" }] }, { id: 2, name: "ROOT-2", children: [{ id: 21, name: "ROOT-21" }, { id: 22, name: "ROOT-22" }] }, { id: 3, name: "ROOT-3", children: [{ id: 31, name: "ROOT-31" }, { id: 32, name: "ROOT-32" }] }] }]
console.log(getParent(data, 'ROOT-0')); // undefined no parent found
console.log(getParent(data, 'ROOT-1')); // ROOT-0
console.log(getParent(data, 'ROOT-11')); // ROOT-1
console.log(getParent(data, 'ROOT-31')); // ROOT-3
.as-console-wrapper { max-height: 100% !important; top: 0; }

filter an array of nested objects in 5 level

I am trying filter this array with .filter.
var objList = [
{
"name": "Object0Name",
"id": "Object0ID",
"Object1List": [
{
"id": "Object1id_A1",
"name": "Object1Name_A1",
"Object2List": [
{
"id": 187,
"name": "Object2Name_A1",
"Object3List": [
{
"id": "mammal",
"name": "mammal",
"Object4List": [
{
"id_client": "rabbit",
"Currency": "EUR"
},
{
"id_client": "cat",
"Currency": "EUR",
},
{
"id_client": "tiger",
"Currency": "EUR",
}
]
}
]
}
]
},
{
"id": "Object1id_B1",
"name": "Object1Name_B1",
"Object2List": [
{
"id": 189,
"name": "Object2Name_B1",
"Object3List": [
{
"id": "fish",
"name": "fish",
"Object4List": [
{
"id_client": "tiger shark",
"Currency": "EUR",
},
{
"id_client": "tuna",
"currency": "GBP",
},
]
}
]
}
]
}
]
}
]
var response= objList.filter(function(Object0List){
return Object0List.Object1List.filter(function(Object1List){
return Object1List.Object2List.filter(function(Object2List){
return Object2List.Object3List.filter(function(Object3List){
return Object3List.Object4List.filter(function(Object4List){
return Object4List.id_client==="tiger shark";
});
});
});
});
});
var myJSON = JSON.stringify(response);
console.log('The animal is:');
console.log(myJSON);
But the filter doesn't work. I am receiving all objects. I must receive:
[
{
"name": "Object0Name",
"id": "Object0ID",
"Object1List": [
{
"id": "Object1id_B1",
"name": "Object1Name_B1",
"Object2List": [
{
"id": 189,
"name": "Object2Name_B1",
"Object3List": [
{
"id": "fish",
"name": "fish",
"Object4List": [
{
"id_client": "tiger shark",
"Currency": "EUR",
}
]
}
]
}
]
}
]
}
]
Could someone help me find out what I'm doing wrong? I'm sure the problem is that I'm using the .filter function badly but it took several hours and I'm not capable of fixing it. I think that I do not understand this function for nested objects, I tried to filter the array of nested objects with lambda expressions but I'm also not able.
Thanks you very much.
You could check each property which is an array and take only filtered values.
This approach mutates the original array.
function filter(array, value) {
var temp = array.filter(o =>
Object.keys(o).some(k => {
var t = filter(Array.isArray(o[k]) ? o[k] : [], value);
if (o[k] === value) {
return true;
}
if (t && Array.isArray(t) && t.length) {
o[k] = t;
return true;
}
})
);
if (temp.length) {
return temp;
}
}
var array = [{ name: "Object0Name", id: "Object0ID", Object1List: [{ id: "Object1id_A1", name: "Object1Name_A1", Object2List: [{ id: 187, name: "Object2Name_A1", Object3List: [{ id: "mammal", name: "mammal", Object4List: [{ id: "rabbit", Currency: "EUR" }, { id: "cat", Currency: "EUR" }, { id: "tiger", Currency: "EUR" }] }] }] }, { id: "Object1id_B1", name: "Object1Name_B1", Object2List: [{ id: 189, name: "Object2Name_B1", Object3List: [{ id: "fish", name: "fish", Object4List: [{ id: "tiger shark", Currency: "EUR" }, { id: "tuna", currency: "GBP" }] }] }] }] }],
result = filter(array, 'tiger shark');
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I assume that every of your objects has this structure:
{
id: "sth",
name: "whatever"
children: [ /***/ ]
}
So then it is quite easy to filter recursively:
function filter(arr, search){
const result = [];
for(const {name, id, children} of arr){
children = filter(children, search);
if(children.length || id === search)
result.push({id, name, children });
}
return result;
}
Usable as:
var response = filter(objList, "tiger shark");

traversing through JSON string to inner levels using recursive function

I have a JSON input which can go to any number of levels.
I'm giving an input sample of
var d=getEntities( {"Categories":
{
"Facets":
[
{
"count": 1,
"entity": "Company",
"Company":
[
{
"entity": "Ford Motor Co",
"Ford_Motor_Co":
[
{
"count": 1,
"entity": "Ford"
}
]
}
]
},
{
"count": 4,
"entity": "Country",
"Country": [
{
"entity": "Germany",
"Germany": [
{
"count": 1,
"entity": "Germany"
}
],
"currency": "Euro (EUR)"
},
{
"entity": "Italy",
"Italy": [
{
"count": 1,
"entity": "Italy"
}
],
"currency": "Euro (EUR)"
},
{
"entity": "Japan",
"Japan": [
{
"count": 1,
"entity": "Japan"
}
],
"currency": "Yen (JPY)"
},
{
"entity": "South Korea",
"South_Korea": [
{
"count": 1,
"entity": "South Korea"
}
],
"currency": "Won (KRW)"
}
]
},
{"count": 5,
"entity": "Persons",
"Persons": [
{
"count": 2,
"entity": "Dodge"
},
{
"count": 1,
"entity": "Dodge Avenger"
},
{
"count": 1,
"entity": "Major League"
},
{
"count": 1,
"entity": "Sterling Heights"
}
]
}
]
}});
I want to add the key value "Entity" in all levels to an array using recursion,
I'm able to collect the data from first level using the string
<html>
<head>
<script src="jquery.js" type="text/javascript"></script>
<script type="text/javascript" src="dataDumper.js"></script>
<script type="text/javascript">
var testJSON = {"Categories":
{
"Facets":
[
{
"count": 1,
"entity": "Company",
"Company":
[
{
"entity": "Ford Motor Co",
"Ford_Motor_Co":
[
{
"count": 1,
"entity": "Ford"
}
]
}
]
},
{
"count": 4,
"entity": "Country",
"Country": [
{
"entity": "Germany",
"Germany": [
{
"count": 1,
"entity": "Germany"
}
],
"currency": "Euro (EUR)"
},
{
"entity": "Italy",
"Italy": [
{
"count": 1,
"entity": "Italy"
}
],
"currency": "Euro (EUR)"
},
{
"entity": "Japan",
"Japan": [
{
"count": 1,
"entity": "Japan"
}
],
"currency": "Yen (JPY)"
},
{
"entity": "South Korea",
"South_Korea": [
{
"count": 1,
"entity": "South Korea"
}
],
"currency": "Won (KRW)"
}
]
},
{"count": 5,
"entity": "Persons",
"Persons": [
{
"count": 2,
"entity": "Dodge"
},
{
"count": 1,
"entity": "Dodge Avenger"
},
{
"count": 1,
"entity": "Major League"
},
{
"count": 1,
"entity": "Sterling Heights"
}
]
}
]
}};
function scan(obj)
{
var k;
if (obj.hasOwnProperty('entity')) {
for (k in obj){
if (obj.hasOwnProperty(k)){
scan( obj[k] );
}
}
}
else{
if(k=='entity')
{
alert(obj.entity);
}
}
};
scan(testJSON);
</script>
</head>
<body>
</body>
</html>
How do I get in to the inner levels for JSON string using recursive functions?
I have made a jsfiddle which traverses every object,array and value in the JS object like so...
function scan(obj) {
var k;
if (obj instanceof Object) {
for (k in obj){
if (obj.hasOwnProperty(k)){
//recursive call to scan property
scan( obj[k] );
}
}
} else {
//obj is not an instance of Object so obj here is a value
};
};
I get no recursion error (in Chrome). Can you use this to do what you want?
If you need to test if an object is an array use if (obj instanceof Array)
To test if an object has an "entity" property use if (obj.hasOwnProperty('entity'))
To add (or modify an existing) "entity" property use obj.entity = value or obj['entity'] = value
(function recur( obj ) {
Object.keys( obj ).forEach( function( prop ) {
// Check if the property is an object
if ( ({}).toString.apply( prop ) === '[object Object]' ) {
// If it is, recall this function
recur( prop );
}
} );
} () );
I haven't added your logic, but you get the idea of how to recursively traverse your object.
Say I have a structure like the following:
var aObject = {
items: [],
children: {}
}
Children is an associative array that contains more aObjects. So it could look like this:
var aObject = {
items: [],
children: {
"subgroup1": {
items: [],
children: {}
},
"subgroup2": {
items: [],
children: {}
}
}
}
I have an item that contains an array of subgroups:
["subgroup1", "subgroup1a"]
Each subgroup is a 'location'. The item needs to be placed at:
aObject.children[array[0]].children[array[1]].items
At each level, we have to check if children[array[i]] exists, and if not, create it. You can't simply write aObject.children[array[0]].children[array[1]].items.push(item) because children[array[0]] might not already exist and we will get an error.
This can be solved using recursion! (AngularJS)
function recursive(aLevel, aItem, aArray, aIndex){
var lLevel = aLevel;
// If we have reached the end of the array
if (aIndex === aArray.length){
// Insert
aLevel.items.push(aItem);
} else {
// If the subgroup doesn't exist, create it
if (typeof aLevel.children[aArray[aIndex]] === 'undefined'){
aLevel.children[aArray[aIndex]] = {
items: [],
children: {}
};
}
// Move into
recursive(aLevel.children[aArray[aIndex]], aItem, aArray, aIndex+1);
}
}
aObject = {
items: [],
children: {},
}
angular.forEach(items, function(item, i){
var location = item.location;
if (location.length == 0){
aObject.items.push(item);
} else {
recursive(aObject, item, location, 0);
}
});
The final aObject would look like this:
var aObject = {
items: [],
children: {
"subgroup1": {
items: [],
children: {
"subgroup1a": {
items: [item],
children: {}
}
}
},
"subgroup2": {
items: [],
children: {}
}
}
}
Here is a function that i use often. It's easily modifiable to do many recursive tasks. For example if you add a bail flag you can quickly get the stack or add a callback function that makes it even more general. Anyway that's my 2 cents
var recursiveObjMap = (function(){
var stack = [];
var result = [];
// var bail = false;
return function map(data, key){
if (!$.isArray(data) && !$.isPlainObject(data) ) {
result.push(data);
return false
}
$.each(data, function(i, v){
if (key) stack.push(key);
map(v, i);
stack.pop();
});
return result;
};
})();
recursiveObjMap({a:'b',c:{d:{e:"f"}}}) // ['b', 'f']
const obj = [
{
count: 1,
entity: "Company",
Company: [
{
entity: "Ford Motor Co",
Ford_Motor_Co: [
{
count: 1,
entity: "Ford",
},
],
},
],
},
{
count: 4,
entity: "Country",
Country: [
{
entity: "Germany",
Germany: [
{
count: 1,
entity: "Germany",
},
],
currency: "Euro (EUR)",
},
{
entity: "Italy",
Italy: [
{
count: 1,
entity: "Italy",
},
],
currency: "Euro (EUR)",
},
{
entity: "Japan",
Japan: [
{
count: 1,
entity: "Japan",
},
],
currency: "Yen (JPY)",
},
{
entity: "South Korea",
South_Korea: [
{
count: 1,
entity: "South Korea",
},
],
currency: "Won (KRW)",
},
],
},
{
count: 5,
entity: "Persons",
Persons: [
{
count: 2,
entity: "Dodge",
},
{
count: 1,
entity: "Dodge Avenger",
},
{
count: 1,
entity: "Major League",
},
{
count: 1,
entity: "Sterling Heights",
},
],
},
];
function test(runObj) {
for (let i in runObj) {
typeof runObj[i] == "object" ? test(runObj[i]) : console.log(runObj[i]);
}
}
test(obj);

Categories

Resources