take JSON input and store it in to an array (javascript) - javascript

I have a JSON input of
{
"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 need to get the values for entity in each level in to an array..
[Company, Ford Motor Co, Ford, ....... , Sterling Heights]
I am able to get thru the first level with the code
for (var k in h.Categories.Facets)
{
alert(h.Categories.Facets[k].entity);
}
How do I reach thru the innerlevels to get the values of entity??

You should do a foreach on each entity. If you know how many levels there are you can nest loops. If not - probably should go for a recursive function.
Edit
Recursive function:
function getEntities(ent)
{
alert(ent);
for (var l in ent)
{
getEntities(ent[l].entity);
}
}
Then use:
for (var k in h.Categories.Facets)
{
getEntities(h.Categories.Facets[k]);
}
Good luck!

The most general recursive answer:
function getEntities(any) {
var entities = [];
if ('entity' in any​) {
entities.push(any.entity);
}
for (var prop in any) {
if (any[prop] instanceof Object && any.hasOwnProperty(prop)) {
entities.append(getEntities(any[prop]));
}
}
return entities;
}
console.log(getEntities(h));
The line:
if (any[prop] instanceof Object && any.hasOwnProperty(prop)) {
Keeps numbers/nulls from bombing and the any.hasOwnProperty(prop) makes up for frameworks that like to attach to the Object prototype.

One way is to write a recursive method that accepts an array and extracts the methods from it.

As suggested, you can use a recursive function to loop through every possible nested combo:
var allEntities = [];
function getEntities(obj)
{
if (obj != null)
{
var entityName = obj["entity"];
alert(entityName);
if (entityName != null)
{
allEntities.push(entityName);
var adjName = entityName.replace(/ /gi, "_");
var entities = obj[adjName];
if (entities != null)
{
for (var e in entities)
{
var innerEntities = getEntities(entities[e]);
for (var inner in innerEntities)
allEntities.push(innerEntities[inner]);
}
}
}
}
}
for (var k in h.Categories.Facets)
{
alert(h.Categories.Facets[k].entity);
getEntities(h.Categories.Facets[k]);
}
alert(allEntities.length);

Related

How to add a new array to a JSON object without creating duplicate array brackets

These nested for loops loop through JSON object containing product categories and subcategories. It loops through these sending a URL parameter to a function to scrape a website according to the parameter. I cant find a way to add the returned arrays containing scraped data to the JSON object (according to its place in the nested loop) without having to create an empty array first and then use .push to populate it, thus duplicating the array brackets. The function returning the scraped data already add the data to an array, so I'm not sure how to go about this.
The following loops add the correct data to the JSON object, however the array brackets are tripled.
for (let i=0; i<obj.length; i++) {
let subcats = obj[i].subcategories;
for(let n=0; n<subcats.length; n++) {
if(!subcats.facetValueData) {
subcats[n].code.replace(/\s/g, '')
let productDataSub = []
subcats[n].productData = productDataSub
subcats[n].productData.push(await scrapeData(obj[i].subcategories[n].code))
} else {
let subcatsFinal = subcats[n].facetValueData
for(let p=0; p<subcatsFinal.length; p++) {
subcatsFinal[p].code.replace(/\s/g, '')
let productData = []
subcatsFinal[p].productData = productData
subcatsFinal[p].productData.push(await scrapeData(obj[i].subcategories[n].facetValueData[p].code))
}
}
}
}
The following is the JSON data being looped, the productData=[] is an example of where the productData array should go, but it is not present when the data is being looped. It is what I'm trying to achieve, but with the data populated inside. The "code" value is the parameter which is appended to a url to scrape that pages data.
[
{
"id": 0,
"categoryName": "Beauty",
"subcategories": [
{
"count": 2688,
"code": "/beauty/skin-care",
"name": "Skincare",
"facetValueData": [
{
"count": 682,
"code": "/beauty/skin-care/lotion-serum-and-essence",
"name": "Lotion Serum & Essence",
"productData": []
},
{
"count": 497,
"code": "/beauty/skin-care/moisturiser-and-mist",
"name": "Moisturiser & Mist",
"productData": []
},
{
"count": 354,
"code": "/beauty/skin-care/cleanser-and-exfoliation",
"name": "Cleanser & Exfoliation",
"productData": []
},
{
"count": 345,
"code": "/beauty/skin-care/mask-and-treatment",
"name": "Mask & Treatment",
"productData": []
}
]
},
{
"count": 1549,
"code": "/beauty/makeup",
"name": "Makeup",
"facetValueData": [
{
"count": 653,
"code": "/beauty/makeup/face",
"name": "Face",
"productData": []
},
{
"count": 460,
"code": "/beauty/makeup/makeup-lips",
"name": "Lips",
"productData": []
},
{
"count": 337,
"code": "/beauty/makeup/eyes",
"name": "Eyes",
"productData": []
},
{
"count": 124,
"code": "/beauty/makeup/makeup-cheeks",
"name": "Cheeks",
"productData": []
}
]
}
]
},
{
"id": 1,
"categoryName": "Electronics",
"subcategories": [
{
"count": 526,
"code": "/electronics/audio-devices",
"name": "Audio",
"facetValueData": [
{
"count": 153,
"code": "/electronics/audio-devices/speakers",
"name": "Speakers",
"productData": []
},
{
"count": 145,
"code": "/electronics/audio-devices/earphones",
"name": "Earphones",
"productData": []
},
{
"count": 142,
"code": "/electronics/audio-devices/headphones",
"name": "Headphones",
"productData": []
},
{
"count": 51,
"code": "/electronics/audio-devices/true-wireless-and-airpods",
"name": "True Wireless & Airpods",
"productData": []
}
]
}
]
}
]
Not sure if all that necessary but here is the async function which scraped the pages and returns the arrays:
async function scrapeData(queryParam) {
let pageCounter = 0;
var product = []
var pagination;
try {
do {
var nextPageLink = `currentPage=${pageCounter}&query=::cagCollectionPoint:Departure+from+Singapore:cagCategory:${queryParam}`
var nextUrl = url.concat(nextPageLink)
const response = await axios({
method: "GET",
url: nextUrl,
withCredentials: true,
headers: headers
})
console.log(nextUrl)
product.push(response.data["products"])
pagination = response.data["pagination"]["totalPages"]
pageCounter++;
// console.log(response.data.currentQuery.query.value)
} while (pageCounter<=0)
return product;
} catch (error) {
console.error(error)
}
}

Flatten an object using lodash

I have below this nested object
I need to create an array using this object containing keys. And if keys are object then it should use .dot syntax. and if it is an array then it should give me key.0.keyName. Is it possible to do so?
Output
[
"AllowIPNPayment",
"AllowOnlinePayment",
"MetaData.CreateTime",
"MetaData.LastUpdatedTime",
"CustomField.0.DefinitionId",
"CustomField.0.Name",
"CustomField.0.Type",
...
]
What I have tried is just ugly and does give me expected result. If it is possible with more concise way.
const invoiceObject = { "AllowIPNPayment": false, "AllowOnlinePayment": false, "AllowOnlineCreditCardPayment": false, "AllowOnlineACHPayment": false, "domain": "QBO", "sparse": false, "Id": "16", "SyncToken": "1", "MetaData": { "CreateTime": "2020-03-25T15:10:40-07:00", "LastUpdatedTime": "2020-03-26T11:06:49-07:00" }, "CustomField": [{ "DefinitionId": "1", "Name": "Crew #", "Type": "StringType" }], "DocNumber": "1007", "TxnDate": "2020-03-03", "CurrencyRef": { "value": "USD", "name": "United States Dollar" }, "LinkedTxn": [{ "TxnId": "32", "TxnType": "Payment" }], "Line": [{ "Id": "1", "LineNum": 1, "Description": "Custom Design", "Amount": 750, "DetailType": "SalesItemLineDetail", "SalesItemLineDetail": { "ItemRef": { "value": "4", "name": "Design" }, "UnitPrice": 75, "Qty": 10, "TaxCodeRef": { "value": "NON" } } }, { "Amount": 750, "DetailType": "SubTotalLineDetail", "SubTotalLineDetail": {} } ], "TxnTaxDetail": { "TotalTax": 0 }, "CustomerRef": { "value": "13", "name": "uiool" }, "CustomerMemo": { "value": "Thank you for your business and have a great day!" }, "SalesTermRef": { "value": "3" }, "DueDate": "2020-04-02", "TotalAmt": 750, "ApplyTaxAfterDiscount": false, "PrintStatus": "NeedToPrint", "EmailStatus": "NotSet", "BillEmail": { "Address": "uiikoool" }, "Balance": 450 }
let object = {}
for (let k in invoiceObject) {
if (typeof invoiceObject[k] === "object") {
object[k] = {};
for (let l in invoiceObject[k]) {
object[k][l] = "";
}
} else if (typeof invoiceObject[k] === "array") {
object[k] = [];
for (let l in invoiceObject[k][0]) {
object[k][l] = "";
}
} else {
object[k] = "";
}
}
console.log(object)
You can create a recursive function (getSchema) that checks if a value (val) is an object (arrays included), iterate it with _.flatMap(), and collects the keys until it hits a value which is not an object. It then joins the collected keys and returns the string.
const getSchema = (val, keys = []) =>
_.isObject(val) ? // if it's an object or array
_.flatMap(val, (v, k) => getSchema(v, [...keys, k])) // iterate it and call fn with the value and the collected keys
:
keys.join('.') // return the joined keys
const invoiceObject = { "AllowIPNPayment": false, "AllowOnlinePayment": false, "AllowOnlineCreditCardPayment": false, "AllowOnlineACHPayment": false, "domain": "QBO", "sparse": false, "Id": "16", "SyncToken": "1", "MetaData": { "CreateTime": "2020-03-25T15:10:40-07:00", "LastUpdatedTime": "2020-03-26T11:06:49-07:00" }, "CustomField": [{ "DefinitionId": "1", "Name": "Crew #", "Type": "StringType" }], "DocNumber": "1007", "TxnDate": "2020-03-03", "CurrencyRef": { "value": "USD", "name": "United States Dollar" }, "LinkedTxn": [{ "TxnId": "32", "TxnType": "Payment" }], "Line": [{ "Id": "1", "LineNum": 1, "Description": "Custom Design", "Amount": 750, "DetailType": "SalesItemLineDetail", "SalesItemLineDetail": { "ItemRef": { "value": "4", "name": "Design" }, "UnitPrice": 75, "Qty": 10, "TaxCodeRef": { "value": "NON" } } }, { "Amount": 750, "DetailType": "SubTotalLineDetail", "SubTotalLineDetail": {} } ], "TxnTaxDetail": { "TotalTax": 0 }, "CustomerRef": { "value": "13", "name": "uiool" }, "CustomerMemo": { "value": "Thank you for your business and have a great day!" }, "SalesTermRef": { "value": "3" }, "DueDate": "2020-04-02", "TotalAmt": 750, "ApplyTaxAfterDiscount": false, "PrintStatus": "NeedToPrint", "EmailStatus": "NotSet", "BillEmail": { "Address": "uiikoool" }, "Balance": 450 }
const result = getSchema(invoiceObject)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
Without lodash, the main change is to use Object.entries() to get an array of [key, value] pairs, since Array.flatMap() can't iterate objects:
const getSchema = (val, keys = []) =>
typeof val === 'object' && val !== null ? // if it's an object or array
Object.entries(val) // get [key, value] pairs of object/array
.flatMap(([k, v]) => getSchema(v, [...keys, k])) // iterate it and call fn with the value and the collected keys
:
keys.join('.') // return the joined keys
const invoiceObject = { "AllowIPNPayment": false, "AllowOnlinePayment": false, "AllowOnlineCreditCardPayment": false, "AllowOnlineACHPayment": false, "domain": "QBO", "sparse": false, "Id": "16", "SyncToken": "1", "MetaData": { "CreateTime": "2020-03-25T15:10:40-07:00", "LastUpdatedTime": "2020-03-26T11:06:49-07:00" }, "CustomField": [{ "DefinitionId": "1", "Name": "Crew #", "Type": "StringType" }], "DocNumber": "1007", "TxnDate": "2020-03-03", "CurrencyRef": { "value": "USD", "name": "United States Dollar" }, "LinkedTxn": [{ "TxnId": "32", "TxnType": "Payment" }], "Line": [{ "Id": "1", "LineNum": 1, "Description": "Custom Design", "Amount": 750, "DetailType": "SalesItemLineDetail", "SalesItemLineDetail": { "ItemRef": { "value": "4", "name": "Design" }, "UnitPrice": 75, "Qty": 10, "TaxCodeRef": { "value": "NON" } } }, { "Amount": 750, "DetailType": "SubTotalLineDetail", "SubTotalLineDetail": {} } ], "TxnTaxDetail": { "TotalTax": 0 }, "CustomerRef": { "value": "13", "name": "uiool" }, "CustomerMemo": { "value": "Thank you for your business and have a great day!" }, "SalesTermRef": { "value": "3" }, "DueDate": "2020-04-02", "TotalAmt": 750, "ApplyTaxAfterDiscount": false, "PrintStatus": "NeedToPrint", "EmailStatus": "NotSet", "BillEmail": { "Address": "uiikoool" }, "Balance": 450 }
const result = getSchema(invoiceObject)
console.log(result)
inspired by the answer given in this post and understanding you just want to get the property-names, not values, you could do it like this. sorry, this uses plain javascript.
function flattenObjectToKeyArray(ob) {
var toReturn = [];
for (var prop in ob) {
if (!ob.hasOwnProperty(prop)) continue;
if ((typeof ob[prop]) == 'object' && ob[prop] !== null) {
var flatObject = flattenObjectToKeyArray(ob[prop]);
for (var idx = 0; idx < flatObject.length; idx++) {
toReturn.push(prop + '.' + flatObject[idx]);
}
} else {
toReturn.push(prop);
}
}
return toReturn;
}
You could solve this with a recursive function. The function below keeps track of the current keys, and joins them as soon as an end point is reached (a non-object or empty object/array).
const invoiceObject = { "AllowIPNPayment": false, "AllowOnlinePayment": false, "AllowOnlineCreditCardPayment": false, "AllowOnlineACHPayment": false, "domain": "QBO", "sparse": false, "Id": "16", "SyncToken": "1", "MetaData": { "CreateTime": "2020-03-25T15:10:40-07:00", "LastUpdatedTime": "2020-03-26T11:06:49-07:00" }, "CustomField": [{ "DefinitionId": "1", "Name": "Crew #", "Type": "StringType" }], "DocNumber": "1007", "TxnDate": "2020-03-03", "CurrencyRef": { "value": "USD", "name": "United States Dollar" }, "LinkedTxn": [{ "TxnId": "32", "TxnType": "Payment" }], "Line": [{ "Id": "1", "LineNum": 1, "Description": "Custom Design", "Amount": 750, "DetailType": "SalesItemLineDetail", "SalesItemLineDetail": { "ItemRef": { "value": "4", "name": "Design" }, "UnitPrice": 75, "Qty": 10, "TaxCodeRef": { "value": "NON" } } }, { "Amount": 750, "DetailType": "SubTotalLineDetail", "SubTotalLineDetail": {} } ], "TxnTaxDetail": { "TotalTax": 0 }, "CustomerRef": { "value": "13", "name": "uiool" }, "CustomerMemo": { "value": "Thank you for your business and have a great day!" }, "SalesTermRef": { "value": "3" }, "DueDate": "2020-04-02", "TotalAmt": 750, "ApplyTaxAfterDiscount": false, "PrintStatus": "NeedToPrint", "EmailStatus": "NotSet", "BillEmail": { "Address": "uiikoool" }, "Balance": 450 };
function getDotKeys(item, keys = []) {
const isObject = item && typeof item == "object";
if (!isObject) return Array.of(keys.join("."));
const pairs = Array.isArray(item)
? item.map((value, index) => [index, value])
: Object.entries(item);
const isEmpty = !pairs.length;
if (isEmpty) return Array.of(keys.join("."));
const result = [];
for (const [key, value] of pairs) {
const dotKeys = getDotKeys(value, [...keys, key]);
result.push(...dotKeys);
}
return result;
}
console.log(getDotKeys(invoiceObject));
This does produce a different result than what you have in your question, since your solution stops at the second level for objects and third level for arrays. This solution also includes more then only index 0.

Underscorejs:How to create a new object by combining values from two objects?

I came across the following scenario
var obj1= [
{
"id": 97,
"name": "Sample1",
"classId": 751,
"gradeId": 1,
"studentId": 1
},
{
"id": 98,
"name": "Sample2",
"classId": 751,
"gradeId": 1,
"studentId": 2
},
{
"id": 97,
"name": "Sample1",
"classId": 751,
"gradeId": 2,
"studentId": 3
},
{
"id": 98,
"name": "Sample2",
"classId": 751,
"gradeId": 2,
"studentId": 4
}
]
Now ,If the id's are same,I need to combine the identical object values in the following form
var obj2=[
{
"id": 97,
"name": "Sample1",
"classId": 751,
"rating":[
{
"gradeId": 1,
"studentId": 1
}
{
"gradeId": 2,
"studentId": 3
}
]
},
{
"id": 98,
"name": "Sample2",
"classId": 751,
"rating":[
{
"gradeId": 1,
"studentId": 2
}
{
"gradeId": 2,
"studentId": 4
}
]
}
]
I am looping through all the objects and ifnthe id's are same I am creating a new object with the combined values,which i feel a little bit elaborated
Can i achieve this through underscore js in a more abstract way?
_.groupBy will do what you want, then use pick/omit to map the groups to the nested objects as you want them:
var obj2 = _.map(_.groupBy(obj1, "id"), function(group) {
var o = _.omit(group[0], "gradeId", "studentId");
o.rating = _.map(group, function(s) {
return _.pick(s, "gradeId", "studentId");
});
return o;
});

looping through JSON object to get to the content of an array

I am breaking my head over this bit of code:
{
"Carrefour": [
{ "geography": [ "Europe", "Germany" ], "productLine": "Produce", "revenue": { "2022": 130143, "2021": 172122, "2020": 103716 } },
{ "geography": [ "Europe", "France" ], "productLine": "Clothing", "revenue": { "2022": 85693, "2021": 91790, "2020": 77650 } },
],
"Tesco": [
{ "geography": [ "Europe", "United Kingdom" ], "productLine": "Electronics", "revenue": { "2022": 239537, "2021": 131959, "2020": 97047 } },
{ "geography": [ "Europe", "Ireland" ], "productLine": "Produce", "revenue": { "2022": 74963, "2021": 43406, "2020": 54623 } },
]
}
I am trying to loop through this code to get to all the content.
But to begn with I don't know how to get to the region (Europe). I tried
function (json) {
for (var company in json) {
region = json[company].geography[0];
}
}
But it returns undefined, because company is an array. Infact json.Carrefour[0].geography[0]; returns correctly "Europe".
how do I access company as an array and retain the name? I can't use the name directly!
Thank you.
Your companies are assigned Arrays, so you need an inner loop.
for (var company in json) {
for (var i = 0; i < json[company].length; i++) {
region = json[company][i].geography[0];
}
}
Here's a demo: http://jsfiddle.net/dkPWt/
Demo output:
Carrefour:
Europe
Europe
Tesco:
Europe
Europe

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