How to transform path list to JSON parent child - javascript

I have a list of paths like this :
var paths = [
"/org/openbmc/UserManager/Group",
"/org/openbmc/records/events",
"/org/openbmc/HostServices",
"/org/openbmc/UserManager/Users",
"/org/openbmc/records/transactions",
"/org/openbmc/UserManager/Groups",
];
And I would like to transform it into a JSON to have this :
var list = {
"name": "org",
"path": "/org",
"children": [
{
"name": "openbmc",
"path": "/org/openbmc",
"children": [
{
"name": "UserManager",
"path": "/org/openbmc/UserManager",
"children": [
{
"name": "Group",
"path": "/org/openbmc/UserManager/Group"
},
{
"name": "Users",
"path": "/org/openbmc/UserManager/users"
},
{
"name": "Groups",
"path": "/org/openbmc/UserManager/Groups"
}
]
},
{
"name": "records",
"path": "/org/openbmc/records",
"children": [
{
"name": "events",
"path": "/org/openbmc/records/events"
},
{
"name": "transactions",
"path": "/org/openbmc/records/transactions"
}
]
}
]
}
]
}
Seems many node.js lib can do this, but I cant find in Javascript the exact same structure. Do you have an idea ?

Related

JavaScript deletes a single item of data from a multidimensional array

Arrays are not fixed, so I think we need to use recursion. Here's the array and my solution :Not implemented yet.
Remove all data where ‘tag’ = 'user'
An array of
var arr = [
{
"name": "ORG_1",
"tag": "org",
"children": [
{
"name": "ORG_1-1",
"tag": "org",
"children": [
{ "name": "USER_1-1-1", "tag": "user" },
{ "name": "USER_1-1-2", "tag": "user" }
]
},
{ "name": "ORG_1-2", "tag": "org", "children": [] },
{ "name": "USER_1-3", "tag": "user" },
{ "name": "USER_1-4", "tag": "user" }
]
},
{
"name": "ORG_2",
"tag": "org",
"children": [
{
"name": "ORG_2-1",
"tag": "org",
"children": [
{ "name": "USER_2-1-1", "tag": "user" },
{ "name": "USER_2-1-2", "tag": "user" }
]
},
{ "name": "ORG_2-2", "tag": "org", "children": [] },
{ "name": "USER_2-3", "tag": "user" },
{ "name": "USER_2-4", "tag": "user" }
]
}
]
I want to delete the object in the array whose 'type' is 'user'.
Here is my code
Code 1
const fun1 = treeList => {
treeList.forEach((item, index) => {
item.tag == 'user' && (treeList.splice(index, 1))
item.children.length && fun1(item.children)
})
}
fun1(arr)
Code 2
const fun2 = treeList => {
treeList = treeList.filter(({ tag }) => tag === 'org')
treeList.forEach((item) => {
item.children.length && fun2(item.children)
})
}
fun2(arr)
This is what I expected, Remove all data where ‘tag’ = 'user'
[
{
"name": "ORG_1",
"tag": "org",
"children": [
{
"name": "ORG_1-1",
"tag": "org",
"children": []
},
{ "name": "ORG_1-2", "tag": "org", "children": [] }
]
},
{
"name": "ORG_2",
"tag": "org",
"children": [
{
"name": "ORG_2-1",
"tag": "org",
"children": []
},
{ "name": "ORG_2-2", "tag": "org", "children": [] }
]
}
]
You can create a function called removeUsers, where you can .map() your array of data, for each object that you map, you can create a new object that contains all the keys from the currently iterated object, along with a new children key that is added only if the currently mapped object has a children key. The value of that children key is a filtered version of the current children array, that removes the objects where the tag is user. You can pass this filtered array of objects into a recursive call to removeUsers to remove the users within those objects' children arrays:
const arr = [ { "name": "ORG_1", "tag": "org", "children": [ { "name": "ORG_1-1", "tag": "org", "children": [ { "name": "USER_1-1-1", "tag": "user" }, { "name": "USER_1-1-2", "tag": "user" } ] }, { "name": "ORG_1-2", "tag": "org", "children": [] }, { "name": "USER_1-3", "tag": "user" }, { "name": "USER_1-4", "tag": "user" } ] }, { "name": "ORG_2", "tag": "org", "children": [ { "name": "ORG_2-1", "tag": "org", "children": [ { "name": "USER_2-1-1", "tag": "user" }, { "name": "USER_2-1-2", "tag": "user" } ] }, { "name": "ORG_2-2", "tag": "org", "children": [] }, { "name": "USER_2-3", "tag": "user" }, { "name": "USER_2-4", "tag": "user" } ] } ];
const removeUsers = arr => arr.map((obj) => ({
...obj,
...(obj.children && {children: removeUsers(obj.children.filter(obj => obj.tag !== "user"))})
}));
console.log(removeUsers(arr));
const filterByTag = (arr, tag) => {
return arr.reduce((acc, item) =>
item.tag !== tag && item.children
? [...acc, { ...item, children: filterByTag(item.children, tag) }]
: acc,
[]);
};
console.log(filterByTag(arr, "user"));

Need to modify BE response to expected response at FE

BE Response:- which I am getting from Backend Service
{
"data": {
"type": "AnyType",
"resources": [
{
"id": 1,
"treeId": "1",
"name": "name1",
"description": "description1",
"children": [
{
"id": 3,
"treeId": "1-3",
"name": "subName1",
"description": "subDescription1",
"children": [
{
"id": 6,
"treeId": "1-3-6",
"name": "subSubName1",
"description": "subSubDesc1",
"children": []
}
]
}
]
},
{
"id": 2,
"treeId": "2",
"name": "name2",
"description": "description2",
"children": [
{
"id": 7,
"treeId": "2-7",
"name": "subName2",
"description": "subDescription2",
"children": []
}
]
}
]
}
}
But I need to modify this response to as below on FE
Expected Response:- means I need to join name and description field text to one(in name field ) as below:-
{
"data": {
"type": "AnyType",
"resources": [
{
"id": 1,
"treeId": "1",
"name": "name1-description1",
"description": "description1",
"children": [
{
"id": 3,
"treeId": "1-3",
"name": "subName1-subDescription1",
"description": "subDescription1",
"children": [
{
"id": 6,
"treeId": "1-3-6",
"name": "subSubName1-subSubDesc1",
"description": "subSubDesc1",
"children": []
}
]
}
]
},
{
"id": 2,
"treeId": "2",
"name": "name2-description2",
"description": "description2",
"children": [
{
"id": 7,
"treeId": "2-7",
"name": "subName2-subDescription2",
"description": "subDescription2",
"children": []
}
]
}
]
}
}
there could be n number of children of each object and children can have an array of objects.
What I have done:- I am able to change the very first name but not children name
let resDataArry = [];
let descData: DynamicResource;
response.forEach((x, index) => {
const descName = x.name + ' ' + x.description;
descData = { ...tree.resources[index], name: descName };
resDataArry.push(descData);
});
return resDataArry;
Please help.
You can use nested Array#forEach to access children array and then concatenate the name and description together.
let data = {
"data": {
"type": "AnyType",
"resources": [
{
"id": 1,
"treeId": "1",
"name": "name1",
"description": "description1",
"children": [
{
"id": 3,
"treeId": "1-3",
"name": "subName1",
"description": "subDescription1",
"children": [
{
"id": 6,
"treeId": "1-3-6",
"name": "subSubName1",
"description": "subSubDesc1",
"children": []
}
]
}
]
},
{
"id": 2,
"treeId": "2",
"name": "name2",
"description": "description2",
"children": [
{
"id": 7,
"treeId": "2-7",
"name": "subName2",
"description": "subDescription2",
"children": []
}
]
}
]
}
}
data.data.resources.forEach(function(item){
item.name = item.name + ' ' + item.description;
item.children.forEach(function(child){
child.name = child.name + ' ' + child.description;
});
});
console.log(data);

Get parent object from key or its value in a nested object

I have an object which contains all information about folders and files of a directory in hierarchical manner.
for example
{
"path": "./parent",
"name": "parent",
"type": "folder",
"children": [
{
"path": "./parent/child1",
"name": "child1",
"type": "folder",
"children": [
{
"path": "./parent/child1/file1",
"name": "file1",
"size": 651956838,
"extension": ".pdf",
"type": "file"
},
{
"path": "./parent/child1/file2",
"name": "file2",
"size": 468327031,
"extension": ".pdf",
"type": "file"
}
]
},
{
"path": "./parent/child2",
"name": "child2",
"type": "folder",
"children": [
{
"path": "./parent/child2/file3",
"name": "file1",
"size": 651956838,
"extension": ".pdf",
"type": "file"
},
{
"path": "./parent/child2/file4",
"name": "file2",
"size": 468327031,
"extension": ".pdf",
"type": "file"
}
]
}
]
}
Now, I will have the path value and from this information I want to access the children property, which is sibling to the key of which that path was value of.
Say, I have path "./parent/child1", then I want to have the value of children property relative to this path which will be
[
{
"path": "./parent/child1/file1",
"name": "file1",
"size": 651956838,
"extension": ".pdf",
"type": "file"
},
{
"path": "./parent/child1/file2",
"name": "file2",
"size": 468327031,
"extension": ".pdf",
"type": "file"
}
]
So I want to know if it is possible or not. If yes then how and if not then is there any other way to achieve similar result?
This can be done using a recursive function.
const paths = {
"path": "./parent",
"name": "parent",
"type": "folder",
"children": [
{
"path": "./parent/child1",
"name": "child1",
"type": "folder",
"children": [
{
"path": "./parent/child1/file1",
"name": "file1",
"size": 651956838,
"extension": ".pdf",
"type": "file"
},
{
"path": "./parent/child1/file2",
"name": "file2",
"size": 468327031,
"extension": ".pdf",
"type": "file"
}
]
},
{
"path": "./parent/child2",
"name": "child2",
"type": "folder",
"children": [
{
"path": "./parent/child2/file3",
"name": "file1",
"size": 651956838,
"extension": ".pdf",
"type": "file"
},
{
"path": "./parent/child2/file4",
"name": "file2",
"size": 468327031,
"extension": ".pdf",
"type": "file"
}
]
}
]
}
const pathtofind = "./parent/child1";
function findChildrenInPath(object, path) {
if (path.startsWith(object.path)) {
if (object.path == path) {
return object.children;
}
else {
for (let child of object.children) {
const result = findChildrenInPath(child, path);
if (result) {
return result;
}
}
}
}
}
const res = findChildrenInPath(paths, pathtofind);
console.log(res);
And here is another approach, without recursion:
const data={
"path": "./parent",
"name": "parent",
"type": "folder",
"children": [
{
"path": "./parent/child1",
"name": "child1",
"type": "folder",
"children": [
{
"path": "./parent/child1/file1",
"name": "file1",
"size": 651956838,
"extension": ".pdf",
"type": "file"
},
{
"path": "./parent/child1/file2",
"name": "file2",
"size": 468327031,
"extension": ".pdf",
"type": "file"
}
]
},
{
"path": "./parent/child2",
"name": "child2",
"type": "folder",
"children": [
{
"path": "./parent/child2/file3",
"name": "file1",
"size": 651956838,
"extension": ".pdf",
"type": "file"
},
{
"path": "./parent/child2/file4",
"name": "file2",
"size": 468327031,
"extension": ".pdf",
"type": "file"
}
]
}
]
};
function getChildrenOf(fs,pth){
let ptha=pth.split('/');
ptha.forEach((d,i,a)=>a[i]=(i?a[i-1]+'/':'')+d);
// console.log(ptha);
return ptha.filter(d=>d!==".").reduce((a,c)=>
a=a.find(d=>d.path===c && d.type==="folder").children
,[fs]);
}
console.log(getChildrenOf(data,"./parent/child1"));
As the data array does not contain any information about the current directory (./) I remove that element from the ptha array. Otherwise the search will allow searches in arbitrary depths of file structures.

Paasing an object into an array of arrays

Have an object that needs to be pass inside the array of source using javascript,throwing an error spec is undefined when using push function. will push function work for this scenario
var a = [
"name": "ben",
"type": "male",
"appType": "human",
"spec": {
"view": "instanceview",
"sink": {
"source": [{
"data": {
"path": "google/path",
"name": "test",
"Id": "11234",
},
"ref": "www.xyz.com",
"id": "isdfjsbfjsfb",
"resourceType": "app"
}
],
},
},
}]
var b = {
"data": {
"path": "google/path",
"name": "goldengate",
"Id": "11234vndslknvlsmnv",
},
"ref": "www.xyz.com",
"id": "6452367e5375",
"resourceType": "app"
}
a.spec.sink.source.push(b);
would expect b to be pushed to source
An array with string keys is not a valid structure, you need to convert a to an object
var a = { // <-- here
"name": "ben",
"type": "male",
"appType": "human",
"spec": {
"view": "instanceview",
"sink": {
"source": [
{
"data": {
"path": "google/path",
"name": "test",
"Id": "11234",
},
"ref": "www.xyz.com",
"id": "isdfjsbfjsfb",
"resourceType": "app"
}
],
},
},
} // <-- here

d3.js how to properly massage my data for tree layout?

I'm having a hard time finding the right way to properly structure my json data to achieve what I need with d3.js.
My content is made of "articles", which have "tags" in a many-to-many relationship.
Therefore, an article can have several tags, a tag can have several articles.
I want to represent my content as a node tree, in such way:
But right now, tags and posts are reproduced several times, as such:
How can I avoid the tag & posts duplication, and instead have lines pointing to the correct nodes? Or is there a better way to format my json data to achieve this sort of visualisation?
You can see my code in action at this fiddle.
Here is the data:
var json_data= {
"name": "Histoire du Web",
"children": [
{
"name": "américain",
"type": "tag",
"count": "1",
"children": [
{
"name": "jeff atwood",
"type": "article",
"count": 7
}
]
},
{
"name": "american",
"type": "tag",
"count": "2",
"children": [
{
"name": "Doug Englebart",
"type": "article",
"count": 5
},
{
"name": "jeff atwood",
"type": "article",
"count": 7
}
]
},
{
"name": "coding horror",
"type": "tag",
"count": "1",
"children": []
},
{
"name": "développeur",
"type": "tag",
"count": "1",
"children": [
{
"name": "jeff atwood",
"type": "article",
"count": 7
}
]
},
{
"name": "Engelbart's Law",
"type": "tag",
"count": "1",
"children": []
},
{
"name": "entrepreneur",
"type": "tag",
"count": "1",
"children": [
{
"name": "jeff atwood",
"type": "article",
"count": 7
}
]
},
{
"name": "forum",
"type": "tag",
"count": "1",
"children": [
{
"name": "jeff atwood",
"type": "article",
"count": 7
}
]
},
{
"name": "hypertext",
"type": "tag",
"count": "1",
"children": [
{
"name": "Doug Englebart",
"type": "article",
"count": 5
}
]
},
{
"name": "interaction",
"type": "tag",
"count": "1",
"children": [
{
"name": "Doug Englebart",
"type": "article",
"count": 5
}
]
},
{
"name": "mouse",
"type": "tag",
"count": "1",
"children": [
{
"name": "Doug Englebart",
"type": "article",
"count": 5
}
]
},
{
"name": "stackoverflow",
"type": "tag",
"count": "1",
"children": [
{
"name": "jeff atwood",
"type": "article",
"count": 7
}
]
}
]
};
It is not easy to use a tree layout to represent data where nodes share parents, however it is possible and a detailed description can be found here: https://gist.github.com/GerHobbelt/3683278
From the link:
Of course, some brutal hacking, e.g. duplication of partial trees to convert multi-parent to many times the same with single parent, can be applied, but it might be a much better option to use a true graph layout mechanism, such as d3.layout.force, and apply the proper constraints to make it do what you want.

Categories