flattening nested json object - javascript

[
{
"children": [
{
"children": [
{
"dateAdded": 1493033302670,
"id": "1534",
"index": 0,
"parentId": "1",
"title": "data1",
"url": "data2"
},
{
"children": [
{
"dateAdded": 1489571506844,
"id": "1451",
"index": 0,
"parentId": "1401",
"title": "data3",
"url": "data4"
}
],
"dateAdded": 1490363326576,
"dateGroupModified": 1490363326576,
"id": "1401",
"index": 1,
"parentId": "1",
"title": "daily"
},
{
"children": [
{
"dateAdded": 1481787664555,
"id": "1429",
"index": 0,
"parentId": "1407",
"title": "data56",
"url": "data"
},
{
"dateAdded": 1483365608504,
"id": "1430",
"index": 1,
"parentId": "1407",
"title": "data34",
"url": "data55"
}
]
}
]
}
]
}
]
This is a representation of Chrome bookmarks data.
If the object has url property it means that is a bookmark. If it does not have url property it is a folder.
It is a tree structure.
I would like to create flatten object with additional property named type. Like:
[
{
"dateAdded": 1489571506844,
"id": "1451",
"index": 0,
"parentId": "1401",
"title": "title",
"url": "some url",
"type": "bookmark"
},
{
"dateAdded": 1489571506844,
"id": "1451",
"index": 0,
"parentId": "1402",
"title": "title2",
"url": "some url2"
"type": "folder"
}
]
Thanks in advance.

You could use an iterative and recursive approach for getting flat data.
function flatten(array) {
var result = [];
array.forEach(function iter(o) {
var temp = {},
keys = Object.keys(o);
if (keys.length > 1) {
keys.forEach(function (k) {
if (k !== 'children') {
temp[k] = o[k];
}
});
temp.type = 'url' in o ? 'bookmark' : 'folder';
result.push(temp);
}
Array.isArray(o.children) && o.children.forEach(iter);
});
return result;
}
var data = [{ children: [{ children: [{ dateAdded: 1493033302670, id: "1534", index: 0, parentId: "1", title: "data1", url: "data2" }, { children: [{ dateAdded: 1489571506844, id: "1451", index: 0, parentId: "1401", title: "data3", url: "data4" }], dateAdded: 1490363326576, dateGroupModified: 1490363326576, id: "1401", index: 1, parentId: "1", title: "daily" }, { children: [{ dateAdded: 1481787664555, id: "1429", index: 0, parentId: "1407", title: "data56", url: "data" }, { dateAdded: 1483365608504, id: "1430", index: 1, parentId: "1407", title: "data34", url: "data55" }] }] }] }];
console.log(flatten(data));
.as-console-wrapper { max-height: 100% !important; top: 0; }

I've made a function that iterates through an array containing objects. If a given object has a property called children, the function calls itself. If it doesn't, then it gets pushed to a new array flattenedBookmarks.
The Solution
var flattenedBookmarks = [];
flattenBookmarks(bookmarks);
function flattenBookmarks(bookmarks) {
for (var i = 0; i < bookmarks.length; i++) {
var potentialBookmark = bookmarks[i];
if (potentialBookmark.hasOwnProperty("url")) {
potentialBookmark.type = "bookmark";
} else {
potentialBookmark.type = "folder";
}
if (potentialBookmark.hasOwnProperty("children")) {
flattenBookmarks(potentialBookmark.children);
if (potentialBookmark.hasOwnProperty("dateGroupModified")) {
flattenedBookmarks.push(potentialBookmark);
}
} else {
flattenedBookmarks.push(potentialBookmark);
}
}
}
You should probably be returning the flattened array from the function instead of storing it in a new global array flattenedBookmarks, but at least this will get you started.
https://jsfiddle.net/s9ur35re/

The example shows how to do it
data = [
{
"children": [
{
"children": [
{
"dateAdded": 1493033302670,
"id": "1534",
"index": 0,
"parentId": "1",
"title": "data1",
"url": "data2"
},
{
"children": [
{
"dateAdded": 1489571506844,
"id": "1451",
"index": 0,
"parentId": "1401",
"title": "data3",
"url": "data4"
}
],
"dateAdded": 1490363326576,
"dateGroupModified": 1490363326576,
"id": "1401",
"index": 1,
"parentId": "1",
"title": "daily"
},
{
"children": [
{
"dateAdded": 1481787664555,
"id": "1429",
"index": 0,
"parentId": "1407",
"title": "data56",
"url": "data"
},
{
"dateAdded": 1483365608504,
"id": "1430",
"index": 1,
"parentId": "1407",
"title": "data34",
"url": "data55"
}
]
}
]
}
]
}
];
data2 = [];
function search(data) {
for (n in data) {
if (typeof data[n] == 'object') {
if (data[n].id != undefined) {
if (data[n].url != undefined) {
data[n].type="folder";
} else {
data[n].type="bookmark";
}
data2.push(data[n]);
}
search(data[n]);
}
}
}
search(data);
console.log(data2);

Related

Get all its parent nodes path for each child nodes

Hi I have below code running, but I would like to add one more property called path which should consist all its parent node path
Expected output I need something as I have shown for cardTtile, so I need same for each node.
[
{
"id": "cardShop",
"key": "cardShop",
"title": "cardShop",
"selectable": false,
"path":cardShop"
"children": [
{
"id": "cardData",
"key": "cardData",
"title": "cardData",
"parentId": "cardShop",
"path":cardShop.cardData"
"selectable": false,
"children": [
{
"id": "cardTitle",
"key": "cardTitle",
"title": "cardTitle",
"parentId": "cardData",
"path":cardShop.cardData.cardTitle"
"isLeaf": true
},
{
"id": "cardType",
"key": "cardType",
"title": "cardType",
"parentId": "cardData",
"isLeaf": true
},
{
"id": "dtmProductName",
"key": "dtmProductName",
"title": "dtmProductName",
"parentId": "cardData",
"isLeaf": true
},
{
"id": "viewAllCards",
"key": "viewAllCards",
"title": "viewAllCards",
"parentId": "cardData",
"selectable": false,
"children": [
{
"id": "url",
"key": "url",
"title": "url",
"parentId": "viewAllCards",
"isLeaf": true
},
{
"id": "text",
"key": "text",
"title": "text",
"parentId": "viewAllCards",
"isLeaf": true
}
]
}
]
},
{
"id": "eligibilityChecker",
"key": "eligibilityChecker",
"title": "eligibilityChecker",
"parentId": "cardShop",
"selectable": false,
"children": [
{
"id": "header",
"key": "header",
"title": "header",
"parentId": "eligibilityChecker",
"isLeaf": true
},
{
"id": "subHeader",
"key": "subHeader",
"title": "subHeader",
"parentId": "eligibilityChecker",
"isLeaf": true
},
{
"id": "bulletPoints",
"key": "bulletPoints",
"title": "bulletPoints",
"parentId": "eligibilityChecker",
"isLeaf": true
}
]
}
]
}
]
I have below running code example here. I tried to persist parentKey recursively but its not giving me expected output.
const transform = data => {
const loop = (data, parent) => Object.entries(data).map(([key, value]) => {
let additional = parent? {
parentId: parent
}:{}
if(typeof value === 'object' && !Array.isArray(value)){
additional = {
...additional,
selectable: false,
children: loop(value, key)
}
}else{
additional.isLeaf = true
}
return {
id: key,
key,
title: key,
...additional
}
})
return loop(data)
}
let jsonObj = {
"data": {
"cardShop": {
"cardData": {
"cardTitle": "The Platinum Card<sup>®</sup>",
"cardType": "credit-cards",
"dtmProductName": "PlatinumCard",
"viewAllCards": {
"url": "credit-cards/all-cards",
"text": "All Cards"
}
},
"eligibilityChecker": {
"header": "Check your eligibility",
"subHeader": "The Platinum Card®",
"bulletPoints": [
"Only takes a couple of minutes to complete",
"Will not impact your credit rating",
"Allows you to apply with confidence"
]
}
}
}
}
console.log(transform(jsonObj.data))
]
You suggestion would be appreciated
Thanks
You could take another variable for path and add the actual key to it.
const transform = data => {
const loop = (data, parentId, previousPath = '') => Object
.entries(data)
.map(([key, value]) => {
const
additional = parentId ? { parentId } : {},
path = previousPath + (previousPath && '.') + key;
Object.assign(
additional,
value && typeof value === 'object' && !Array.isArray(value)
? { selectable: false, children: loop(value, key, path) }
: { isLeaf: true }
);
return { id: key, key, title: key, path, ...additional };
});
return loop(data);
}
const data = { cardShop: { cardData: { cardTitle: "The Platinum Card<sup>®</sup>", cardType: "credit-cards", dtmProductName: "PlatinumCard", viewAllCards: { url: "credit-cards/all-cards", text: "All Cards" } }, eligibilityChecker: { header: "Check your eligibility", subHeader: "The Platinum Card®", bulletPoints: ["Only takes a couple of minutes to complete", "Will not impact your credit rating", "Allows you to apply with confidence"] } } };
console.log(transform(data));
.as-console-wrapper { max-height: 100% !important; top: 0; }

How to Update value nested array in array jquery

Please help
I tried to edit the second myArray, and in myArray there is myArray[data] which is also an array, how do I update it??
var myArray= [
{
"id": 0,
"item": "DONOMULYO",
"data": [
{
"id": 0,
"field": "satu",
"record": "11"
},
{
"id": 1,
"field": "dua",
"record": ""
}
]
},
{
"id": 1,
"item": "PAGAK",
"data": [
{
"id": 0,
"field": "satu",
"record": "11"
},
{
"id": 1,
"field": "dua",
"record": ""
}
]
},
{
**"id": 2,**
"item": "BANTUR",
"data": [
{
"id": 0,
"field": "satu",
**"record": "11"**
},
{
"id": 1,
"field": "dua",
"record": ""
}
]
},
{
"id": 3,
"item": "SUMBERMANJING WETAN",
"data": [
{
"id": 0,
"field": "satu",
"record": "11"
},
{
"id": 1,
"field": "dua",
"record": ""
}
]
}
]
how to change myArray second data record?
this is my code for change update, but there all data is updated, how to change only myArray third data inside myArray[data] ??
//this is my code for update
var update_array = 2;
var update_inside_array = 0;
var valnya = '12';
var arr_data_edit = myArray[update_array].data;
if(arr_data_edit[update_inside_array].id == update_inside_array){
arr_data_edit[idfiledx].record = valnya;
}
console.log(myArray);
I've tried various ways, this is the last one I ran out of ideas, please help to solve this
Thank you for the help
Your current code should work if you simply change idfiledx to update_inside_array:
var update_array = 2;
var update_inside_array = 0;
var valnya = '12';
var arr_data_edit = myArray[update_array].data;
if(arr_data_edit[update_inside_array].id == update_inside_array){
arr_data_edit[update_inside_array].record = valnya;
}
console.log(myArray);
In general, I think it would probably be better to find the item to be updated (the one that has `id: 2`) regardless of its position in the array.
Here's a way to doing that using the .find method of arrays:
const
myArray = [
{ "id": 0, "item": "DONOMULYO", "data": [
{ "id": 0, "field": "satu", "record": "11" },
{ "id": 1, "field": "dua", "record": "" }
]},
{ "id": 1, "item": "PAGAK", "data": [
{ "id": 0, "field": "satu", "record": "11" },
{ "id": 1, "field": "dua", "record": "" }
]},
{ "id": 2, "item": "BANTUR", "data": [
{ "id": 0, "field": "satu", "record": "11" },
{ "id": 1, "field": "dua", "record": "" }
]},
{ "id": 3, "item": "SUMBERMANJING WETAN", "data": [
{ "id": 0, "field": "satu", "record": "11" },
{ "id": 1, "field": "dua", "record": "" }
]}
],
outerId = 2,
innerId = 0,
newVal = '12',
outerObj = myArray.find(obj => obj.id == outerId),
innerObj = outerObj.data.find(obj => obj.id == innerId);
innerObj.record = newVal;
console.log(myArray);
.as-console-wrapper{min-height: 100%!important; top: 0}
(Btw, it doesn't look like you use or need any jQuery for this.)
You don't need jQuery, you can use either find or filter, here is an example using filter:
var update_array = 2;
var update_inside_array = 0;
var valnya = '12';
var item = myArray[update_array].data.filter(x => x.id == update_inside_array)[0];
if (typeof item !== 'undefined') item.record = valnya;
console.log(myArray);

How to replace an array of objects with an array including newer objects in TypeScript?

For example: I have an array of objects like this:
let arrayOfObjects: [
{ "id": 0, "name": "Available" },
{ "id": 1, "name": "Ready" },
{ "id": 2, "name": "Started" }
];
Now I want to replace or overwrite the array above with the same array, but including different values (same keys, different values):
let arrayOfObjects: [
{ "id": 0, "name": "Not Available" },
{ "id": 1, "name": "Not Ready" },
{ "id": 2, "name": "Not Started" }
];
How can this be done in TypeScript?
Try this JS
let oneArray = [
{ "id": 0, "name": "Available" },
{ "id": 1, "name": "Ready" },
{ "id": 2, "name": "Started" }
];
let twoArray = [
{ "id": 0, "name": "Not Available" },
{ "id": 1, "name": "Not Ready" },
{ "id": 2, "name": "Not Started" }
];
let newArray = Object.assign([], oneArray, twoArray);
console.log(newArray);
In TS
interface Data {
oneArray: array;
twoArray: array;
}
function merge(data: Data) {
return Object.assign([], data.oneArray, data.twoArray);
}
let user = {
oneArray: [
{ "id": 0, "name": "Available" },
{ "id": 1, "name": "Ready" },
{ "id": 2, "name": "Started" }
],
twoArray: [
{ "id": 0, "name": "Not Available" },
{ "id": 1, "name": "Not Ready" },
{ "id": 2, "name": "Not Started" }
]
};
console.log(merge(user));
Sure :)
let arrayOfObjects = [
{ "id": 0, "name": "Available" },
{ "id": 1, "name": "Ready" },
{ "id": 2, "name": "Started" }
];
const newValues = ['Not Available', 'Not Ready', 'Not Started'];
newValues.forEach((value, i) => {
arrayOfObjects.find(o => o.id === i).name = value;
});
console.log(arrayOfObjects);
I wouldn't recommend this though: functional programming is awesome.
let arrayOfObjects = [
{ "id": 0, "name": "Available" },
{ "id": 1, "name": "Ready" },
{ "id": 2, "name": "Started" }
];
let names = ['Not Available', 'Not Ready', 'Not Started']
let result = arrayOfObjects.map((user, index) => ({ ...user, name: names[index] }))
console.log(result)

Search a Javascript Object for the position of a specific ID? [duplicate]

This question already has answers here:
Find by key deep in a nested array
(21 answers)
Closed 4 years ago.
I have a Javascript object with lots of different sections. How can I search through all of the sections to find the position of a specific ID? The ID's that I am searching for are not in a specific location, and can be located in any of the tree branches.
For example, I am searching for this ID:
xobmnbjxg0g_1527269346261
And I am trying to output the position of that ID, which would be this:
app['structure'][0]['if-children'][0]['id']
My Javascript Object:
var app = {
"structure": [
{
"id": "0",
"type":"IF",
"parameters": [
{
"id": "xobmnbjxg0g_1527269346260",
"type": "field",
"value": "CV_TEST_SPOT1X"
},
{
"id": "2",
"type": "operator",
"value": "="
},
{
"id": "3",
"type": "field",
"value": "North America"
}
],
"if-children": [
{
"id": "xobmnbjxg0g_1527269346261",
"type":"IF",
"parameters": [
{
"id": "1",
"type": "field",
"value": "CV_TEST_SPOT1"
},
{
"id": "2",
"type": "operator",
"value": "="
},
{
"id": "3",
"type": "field",
"value": "North America"
}
],
"if-children":[
],
"else-children":[
]
}
],
"else-children":[
{
"id": "xobmnbjxg0g_1527269346262",
"type":"IF",
"parameters": [
{
"id": "1",
"type": "field",
"value": "CV_TEST_SPOT1"
},
{
"id": "2",
"type": "operator",
"value": "="
},
{
"id": "3",
"type": "field",
"value": "North America"
}
],
"if-children":[
{
"id":"xobmnbjxg0g_152726934626X"
}
],
"else-children":[
{
"id":"xobmnbjxg0g_152726934626Y"
}
]
}
]
},
{
"id": "xobmnbjxg0g_1527269346263",
"type":"IF",
"parameters": [
[
{
"id": "1",
"type": "field",
"value": "CV_TEST_SPOT1"
}
]
],
"if-children": [
{
"id": "xobmnbjxg0g_1527269346264",
"type":"IF",
"parameters": [
[
{
"id": "1",
"type": "field",
"value": "CV_TEST_SPOT1"
}
]
],
"if-children":[
{
"id": "xobmnbjxg0g_1527269346265",
"type":"IF",
"parameters": [
{
"id": "1",
"type": "field",
"value": "CV_TEST_SPOT1"
}
],
"if-children":[
{
"id":"xobmnbjxg0g_1527269346266"
}
],
"else-children":[
{
"id":"xobmnbjxg0g_1527269346267"
}
]
}
],
"else-children":[
{
"id":"xobmnbjxg0g_1527269346268"
}
]
}
],
"else-children":[
{
"id":"xobmnbjxg0g_1527269346269"
}
]
}
]
};
Interesting puzzle/question.
pretty sure there are some edge cases im missing but this seems to pass some tests.
function is(obj, type){
return Object.prototype.toString.call(obj) === `[object ${type}]`;
}
function findPosition(obj, mykey, myval, res){
if(is(obj, "Object")){
if(mykey in obj && obj[mykey] === myval){
res.tree.push(mykey);
res.found = true;
} else {
for( let key in obj){
if(res.found) break;
res.tree.push(key);
findPosition(obj[key], mykey, myval, res);
}
if(!res.found) res.tree.pop();
}
} else if(is(obj, "Array")){
for(let i = 0; i < obj.length; i++){
if(res.found) break;
res.tree.push(i);
findPosition(obj[i], mykey, myval, res);
}
if(!res.found) res.tree.pop();
} else {
res.tree.pop();
}
return res;
}
Usage and output
findPosition([{one: { two: [{id: [{id:'my'}]}]}}], "id", "mys", {tree:[], found: false})
> tree: Array(0), found: false}
findPosition([{one: { two: [{id: [{id:'my'}]}]}}], "id", "my", {tree:[], found: false})
> {found: true, tree: [0, "one", "two", 0, "id", 0, "id"]}
For finding if current obj you are iterating over is an Array you can also use Array.isArray

Nesting a parent child relationship in lodash, given the parent id and children

How would I be able to nest json object if the parent and its children was given as a property.
The data looks like:
"1": {
"id": 1,
"name": "foo",
"parent": null,
"root": 1,
"children": [2, 4, 6],
"posts":[
{ "id": "1", "name": "item1" },
{ "id": "2", "name": "item2" },
{ "id": "3", "name": "item3" }
]
},
"2": {
"id": 2,
"name": "bar",
"parent": 1,
"root": 1,
"children": null,
"posts":[
{ "id": "4", "name": "item4" }
]
},
"3": {
"id": 3,
"name": "bazz",
"parent": null,
"root": 3,
"children": [5, 7],
"posts":[
{ "id": "5", "name": "item5" },
{ "id": "6", "name": "item6" }
]
},
....
A simple groupby using lodash won't do it.
var group = _.groupBy(data, 'parent');
Here is a fiddle:
http://jsfiddle.net/tzugzo8a/1/
The context of question is a nested categories with subcategories, and categories can have categories and posts in them.
Basically I don't want to have a different property for children and posts, since they are all children of a parent.
Desired output
"1": {
"id": 1,
"name": "foo",
"parent": null,
"root": 1,
"isCategory": true,
"children": [
{
"id": 2,
"name": "bar",
"parent": 1,
"root": 1,
"isCategory": true,
"children": null
},
{ "id": "1", "name": "item1", isCategory: false },
{ "id": "2", "name": "item2", isCategory: false },
{ "id": "3", "name": "item3", isCategory: false }
]
...
}
This is my take on the question (fiddle):
var data = getData();
var group = getTree(data);
console.log(group);
function getTree(flat) {
return _.reduce(flat, function (treeObj, item, prop, flatTree) {
var children = _.map(item.children, function (childId) {
return _.set(flatTree[childId], 'isCategory', true);
}).concat(_.map(item.items, function(item) {
return _.set(item, 'isCategory', false);
}));
item.children = !!children.length ? children : null;
delete item.items;
item.parent === null && (treeObj[prop] = item);
return treeObj;
}, {});
}
Take a look on the updated fiddle:
var data = getData();
_.keys(data).forEach(function(id){
var element = data[id];
if (element.children === null){
element.children = [];
}
element.isCategory = true;
element.items.forEach(function(item){
item.isCategory = false;
})
});
_.keys(data).forEach(function(id){
var element = data[id];
element.children = element.children.map(function(childId){
return data[childId];
}).concat(element.items);
});
_.keys(data).forEach(function(id){
delete data[id].items;
});
console.log(JSON.stringify(_.findWhere(_.values(data), {'parent': null})));

Categories

Resources