I am trying to build an array of JSON objects for FancyTree (https://github.com/mar10/fancytree/wiki/TutorialLoadData). However, my JSON source (Jira REST service) can have pretty much any structure, so the code to build the array of JSON objects has to be entirely generic and able to handle pretty much anything.
Here is an example of the source JSON:
{
"feed": {
"entry": [
{
"expand": "renderedFields,names,schema,operations,editmeta,changelog,versionedRepresentations",
"id": "95743",
"self": "foo.comjira/rest/api/2/issue/95743",
"key": "XYZ-24600",
"fields": {
"MandatoryReviewersInternal": [
{
"self": "foo.comjira/rest/api/2/customFieldOption/10947",
"value": "Test",
"id": "10947",
"disabled": false
}
],
"PlannedDropDate": "2022-02-01",
"assignee": {
"self": "foo.comjira/rest/api/2/user?username=swchambe",
"name": "swchambe",
"key": "swchambe",
"emailAddress": "sharon.w.chamberlain#foo.com",
"displayName": "Sharon W Chamberlain",
"active": true,
"timeZone": "America/Chicago"
},
"ESBEnvironments": {
"self": "foo.comjira/rest/api/2/customFieldOption/10120",
"value": "All Environments",
"id": "10120",
"disabled": false
},
"RestrictedInformation": "Do not include Proprietary, ITAR or SBU restricted information in this action",
"subtasks": [
{
"id": "96160",
"key": "XYZ-24601",
"self": "foo.comjira/rest/api/2/issue/96160",
"fields": {
"summary": "Test 1",
"status": {
"self": "foo.comjira/rest/api/2/status/10338",
"description": "",
"iconUrl": "foo.comjira/images/icons/statuses/generic.png",
"name": "Current",
"id": "10338",
"statusCategory": {
"self": "foo.comjira/rest/api/2/statuscategory/4",
"id": 4,
"key": "indeterminate",
"colorName": "yellow",
"name": "In Progress"
}
},
"issuetype": {
"self": "foo.comjira/rest/api/2/issuetype/10319",
"id": "10319",
"description": "",
"iconUrl": "foo.comjira/secure/viewavatar?size=xsmall&avatarId=11747&avatarType=issuetype",
"name": "Affected Document",
"subtask": true,
"avatarId": 11747
}
}
},
{
"id": "96466",
"key": "XYZ-24614",
"self": "foo.comjira/rest/api/2/issue/96466",
"fields": {
"summary": "Test 2",
"status": {
"self": "foo.comjira/rest/api/2/status/10338",
"description": "",
"iconUrl": "foo.comjira/images/icons/statuses/generic.png",
"name": "Current",
"id": "10338",
"statusCategory": {
"self": "foo.comjira/rest/api/2/statuscategory/4",
"id": 4,
"key": "indeterminate",
"colorName": "yellow",
"name": "In Progress"
}
},
"issuetype": {
"self": "foo.comjira/rest/api/2/issuetype/10319",
"id": "10319",
"description": "",
"iconUrl": "foo.comjira/secure/viewavatar?size=xsmall&avatarId=11747&avatarType=issuetype",
"name": "Affected Document",
"subtask": true,
"avatarId": 11747
}
}
}
],
"Participants": [
{
"name": "djcook2(djcook2xyz)"
},
{
"name": "swchambe(swchambexyz)"
},
{
"name": "r_slscdm(JIRAxyz)"
}
],
"reporter": {
"self": "foo.comjira/rest/api/2/user?username=djcook2",
"name": "djcook2",
"key": "djcook2",
"emailAddress": "deborah.j.ott#foo.com",
"displayName": "Deborah Jane Ott",
"active": true,
"timeZone": "America/Chicago"
},
"CPEOrganization": "xyz",
"SFSearchandViewLink": "<a href=foo.comportal/web/csa/search?key=95743&projectKey=XYZ&issueType=Change%20Request>S2D-0637</a>",
"progress": {
"progress": 0,
"total": 0
},
"issuetype": {
"self": "foo.comjira/rest/api/2/issuetype/8",
"id": "8",
"description": "Request for a change to the way the application works.",
"iconUrl": "foo.comjira/secure/viewavatar?size=xsmall&avatarId=11737&avatarType=issuetype",
"name": "Change Request",
"subtask": false,
"avatarId": 11737
},
"project": {
"self": "foo.comjira/rest/api/2/project/13390",
"id": "13390",
"key": "XYZ",
"name": "Configuration Status Accounting",
"projectTypeKey": "business"
},
"SFIdentifier": "S2D-0637",
"watches": {
"self": "foo.comjira/rest/api/2/issue/XYZ-24600/watchers",
"watchCount": 2,
"isWatching": true
},
"ServerEnvironment": [
{
"self": "foo.comjira/rest/api/2/customFieldOption/10060",
"value": "Production",
"id": "10060",
"disabled": false
}
],
"ScheduleImpact": {
"self": "foo.comjira/rest/api/2/customFieldOption/12245",
"value": "No",
"id": "12245",
"disabled": false
},
"MissionConfigurationDefinition": [
{
"self": "foo.comjira/rest/api/2/customFieldOption/12246",
"value": "1110-1200",
"id": "12246",
"disabled": false
},
{
"self": "foo.comjira/rest/api/2/customFieldOption/12247",
"value": "1110-2200",
"id": "12247",
"disabled": false
}
],
"updated": "2022-05-23T10:06:45.000-0500",
"description": "¶ Paragraph\nNonbreaking Hyphen\nEm Space\nEn Space\n½ One Half Fraction\n¼ One Quarter Fraction\n¾ Three Quarters Fraction\n10⁵ superscript\n6⁵ superscript\nO₂ subscript\n\n± 0177\n≤ 2264\n≥ 2265\n\n10⁰ - 2070\n10¹ - 00B9\n10³ - 00B3\n10² - 00B2\n10⁴ - 2074\n10⁵ - 2075\n10⁶ - 2076\n10⁷ - 2077\n10⁸ - 2078\n10⁹ - 2079\n\nΑ 0391\nΒ 0392\nΓ 0393\nΔ 0394\nΕ 0395",
"CRStatus": {
"self": "foo.comjira/rest/api/2/customFieldOption/10050",
"value": "In Work",
"id": "10050",
"disabled": false
},
"summary": "SLS-FSW-SAN-21-0010 SLS FSW Software Authorization Notice (SAN) - PARMD5 Support Tool Release 14.0",
"SLSPriority": {
"self": "foo.comjira/rest/api/2/customFieldOption/10347",
"value": "Routine",
"id": "10347",
"disabled": false
},
"TestStatus": [
{
"self": "foo.comjira/rest/api/2/customFieldOption/10041",
"value": "Not Tested",
"id": "10041",
"disabled": false
}
],
"ChangeJustificationRationale": "Looks good to me, but who am I?",
"CostImpact": {
"self": "foo.comjira/rest/api/2/customFieldOption/19251",
"value": "No",
"id": "19251",
"disabled": false
},
"ExternalReviewType": {
"self": "foo.comjira/rest/api/2/customFieldOption/10370",
"value": "Mandatory",
"id": "10370",
"disabled": false
},
"CROffice": {
"self": "foo.comjira/rest/api/2/customFieldOption/10342",
"value": "SLS",
"id": "10342",
"disabled": false
},
"Rank": "0|i0c9r8:",
"CrossProgram": {
"self": "foo.comjira/rest/api/2/customFieldOption/10294",
"value": "No",
"id": "10294",
"disabled": false
},
"Programassignedto": {
"self": "foo.comjira/rest/api/2/customFieldOption/10295",
"value": "SLS",
"id": "10295",
"disabled": false
},
"Programassignedby": {
"self": "foo.comjira/rest/api/2/customFieldOption/10301",
"value": "SLS",
"id": "10301",
"disabled": false
},
"ChangeType": [
{
"self": "foo.comjira/rest/api/2/customFieldOption/10307",
"value": "Programmatic",
"id": "10307",
"disabled": false
}
],
"ChangePackageManagerCPM": {
"self": "foo.comjira/rest/api/2/user?username=swchambe",
"name": "swchambe",
"key": "swchambe",
"emailAddress": "sharon.w.chamberlain#foo.com",
"displayName": "Sharon W Chamberlain",
"active": true,
"timeZone": "America/Chicago"
},
"ChangePackageManagerAlternateCPMAlternate": {
"self": "foo.comjira/rest/api/2/user?username=slcraig",
"name": "slcraig",
"key": "smclemo2",
"emailAddress": "shanda.craig#foo.com",
"displayName": "Shanda L Craig",
"active": true,
"timeZone": "America/Chicago"
},
"ChangePackageEngineerCPE": {
"self": "foo.comjira/rest/api/2/user?username=cbowab",
"name": "cbowab",
"key": "cbowab",
"emailAddress": "cheri.f.bowab#foo.com",
"displayName": "Cheri F Bowab",
"active": true,
"timeZone": "America/Chicago"
},
"status": {
"self": "foo.comjira/rest/api/2/status/10631",
"description": "",
"iconUrl": "foo.comjira/images/icons/statuses/generic.png",
"name": "Draft",
"id": "10631"
},
"Development": "{}",
"RequestedDate": "2021-05-13",
"Risk": {
"self": "foo.comjira/rest/api/2/customFieldOption/10273",
"value": "No",
"id": "10273",
"disabled": false
},
"creator": {
"self": "foo.comjira/rest/api/2/user?username=djcook2",
"name": "djcook2",
"key": "djcook2",
"emailAddress": "deborah.j.ott#foo.com",
"displayName": "Deborah Jane Ott",
"active": true,
"timeZone": "America/Chicago"
},
"aggregateprogress": {
"progress": 0,
"total": 0
},
"AssigneeSecurityScan": {
"self": "foo.comjira/rest/api/2/user?username=sbattles",
"name": "sbattles",
"key": "sbattles",
"emailAddress": "sylvia.battles#foo.com",
"displayName": "Sylvia M Battles",
"active": true,
"timeZone": "America/Chicago"
},
"Board": [
{
"self": "foo.comjira/rest/api/2/customFieldOption/10259",
"value": "XYZ",
"id": "10259",
"disabled": false
}
],
"MissionEffectivity": [
{
"self": "foo.comjira/rest/api/2/customFieldOption/19754",
"value": "XYZ",
"id": "19754",
"disabled": false
},
{
"self": "foo.comjira/rest/api/2/customFieldOption/19756",
"value": "AC01",
"id": "19756",
"disabled": false
}
],
"CRNumber": [
{
"name": "XYZ-0637"
}
],
"created": "2021-05-14T15:14:22.000-0500",
"ASCBBoardDate": "2021-05-18",
"InitiatorOrganization": "ED10",
"CPMAssignedDate": "2021-05-14",
"CRAssignedDate": "2021-05-14",
"ImpactstoCertifiedData": {
"self": "foo.comjira/rest/api/2/customFieldOption/20152",
"value": "No",
"id": "20152",
"disabled": false
},
"ASCBReviewSuspenseDate": "2021-05-18",
"TopLevelLinkTitle": "SV02854 S2D-0637",
"TopLevelLinkURL": "https://nasa-ice.nasa.gov/Windchill/app/#ptc1/tcomp/infoPage?ContainerOid=OR%3Awt.inf.library.WTLibrary%3A3451955009&oid=OR%3Awt.folder.SubFolder%3A4352888087&u8=1",
"Initiator": {
"self": "foo.comjira/rest/api/2/user?username=kmoorhea",
"name": "kmoorhea",
"key": "kmoorhea",
"emailAddress": "kathy.h.moorhead#foo.com",
"displayName": "Kathy H Moorhead",
"active": true,
"timeZone": "America/Chicago"
}
}
}
]
}
}
I need to end up with an array of JSON objects that looks like this:
[
{title: "Node 1", key: "1"},
{title: "Folder 2", key: "2", folder: true, children: [
{title: "Node 2.1", key: "3", myOwnAttr: "abc"},
{title: "Node 2.2", key: "4"},
{title: "Folder 3", key: "5", folder: true, children: [
{title: "Node 3.1", key: "6", myOwnAttr: "xyz"},
{title: "Node 3.2", key: "7"}
]}
]}
]
Here is my current attempt. It is not working as desired.
const createTreeJson = function(){
let treeJson = [];
let treeJsonObj = {};
//loop entry array, but there is only ever 1
feedJson.feed.entry.forEach((entry) => {
treeJsonObj = {};
//items
treeJsonObj.title = "Item";
treeJsonObj.folder = true;
let children = [];
//loop object properties
Object.entries(entry).forEach(([key, value]) => {
children.push(createTreeJsonObject(children, key, value));
});
treeJsonObj.children = children;
treeJson.push(treeJsonObj);
});
console.log(treeJson);
}
const createTreeJsonObject = function(children, key, value){
console.log(key, value);
if(value.constructor.name === "Object"){
//it's an object
let subChildren = [];
Object.entries(value).forEach(([key2, value2]) => {
subChildren.push(createTreeJsonObject(subChildren, key2, value2));
});
children.push({
"title": key,
"folder": true,
"children": subChildren
});
}else if(value.constructor.name === "Array"){
//it's an array
}else{
//it's something else
children.push({
"key": key,
"title": `${key}`,
"tooltip": `${value}`
});
}
return children;
};
createTreeJson();
Note: feedJson in the code is the above source JSON. I did not want to repeat it again in the code. You can also see it in a Fiddle here: https://jsfiddle.net/ua8vm9p7/1/
I am open to using something like loadash to help with this if it makes it easier. I do have jQuery available too, but am trying to stay away from it.
I can't seem to quite get the logic right. Has anyone done this kind of thing before? Can anyone lend a hand on how I can do it?
Thanks.
I think simpler code will do this:
const makeFancyMenu = (obj) =>
Object .entries (obj) .flatMap (([k, v]) =>
Array .isArray (v)
? []
: Object (v) === v
? [{title: k, folder: true, children: makeFancyMenu (v)}]
: [{key: k, title: `${k}`, tooltip: v}]
)
const convert = (obj) =>
obj .feed .entry .map ((o) => ({
title: 'Item',
folder: true,
children: makeFancyMenu (o)
}))
const input = {feed: {entry: [{expand: "renderedFields,names,schema,operations,editmeta,changelog,versionedRepresentations", id: "95743", self: "foo.comjira/rest/api/2/issue/95743", key: "XYZ-24600", fields: {MandatoryReviewersInternal: [{self: "foo.comjira/rest/api/2/customFieldOption/10947", value: "Test", id: "10947", disabled: !1}],PlannedDropDate: "2022-02-01", assignee: {self: "foo.comjira/rest/api/2/user?username=swchambe", name: "swchambe", key: "swchambe", emailAddress: "sharon.w.chamberlain#foo.com", displayName: "Sharon W Chamberlain", active: !0,timeZone: "America/Chicago"},ESBEnvironments: {self: "foo.comjira/rest/api/2/customFieldOption/10120", value: "All Environments", id: "10120", disabled: !1},RestrictedInformation: "Do not include Proprietary, ITAR or SBU restricted information in this action", subtasks: [{id: "96160", key: "XYZ-24601", self: "foo.comjira/rest/api/2/issue/96160", fields: {summary: "Test 1", status: {self: "foo.comjira/rest/api/2/status/10338", description: "", iconUrl: "foo.comjira/images/icons/statuses/generic.png", name: "Current", id: "10338", statusCategory: {self: "foo.comjira/rest/api/2/statuscategory/4", id: 4,key: "indeterminate", colorName: "yellow", name: "In Progress"}},issuetype: {self: "foo.comjira/rest/api/2/issuetype/10319", id: "10319", description: "", iconUrl: "foo.comjira/secure/viewavatar?size=xsmall&avatarId=11747&avatarType=issuetype", name: "Affected Document", subtask: !0,avatarId: 11747}}},{id: "96466", key: "XYZ-24614", self: "foo.comjira/rest/api/2/issue/96466", fields: {summary: "Test 2", status: {self: "foo.comjira/rest/api/2/status/10338", description: "", iconUrl: "foo.comjira/images/icons/statuses/generic.png", name: "Current", id: "10338", statusCategory: {self: "foo.comjira/rest/api/2/statuscategory/4", id: 4,key: "indeterminate", colorName: "yellow", name: "In Progress"}},issuetype: {self: "foo.comjira/rest/api/2/issuetype/10319", id: "10319", description: "", iconUrl: "foo.comjira/secure/viewavatar?size=xsmall&avatarId=11747&avatarType=issuetype", name: "Affected Document", subtask: !0,avatarId: 11747}}}],Participants: [{name: "djcook2(djcook2xyz)"},{name: "swchambe(swchambexyz)"},{name: "r_slscdm(JIRAxyz)"}],reporter: {self: "foo.comjira/rest/api/2/user?username=djcook2", name: "djcook2", key: "djcook2", emailAddress: "deborah.j.ott#foo.com", displayName: "Deborah Jane Ott", active: !0,timeZone: "America/Chicago"},CPEOrganization: "xyz", SFSearchandViewLink: "<a href=foo.comportal/web/csa/search?key=95743&projectKey=XYZ&issueType=Change%20Request>S2D-0637</a>", progress: {progress: 0,total: 0},issuetype: {self: "foo.comjira/rest/api/2/issuetype/8", id: "8", description: "Request for a change to the way the application works.", iconUrl: "foo.comjira/secure/viewavatar?size=xsmall&avatarId=11737&avatarType=issuetype", name: "Change Request", subtask: !1,avatarId: 11737},project: {self: "foo.comjira/rest/api/2/project/13390", id: "13390", key: "XYZ", name: "Configuration Status Accounting", projectTypeKey: "business"},SFIdentifier: "S2D-0637", watches: {self: "foo.comjira/rest/api/2/issue/XYZ-24600/watchers", watchCount: 2,isWatching: !0},ServerEnvironment: [{self: "foo.comjira/rest/api/2/customFieldOption/10060", value: "Production", id: "10060", disabled: !1}],ScheduleImpact: {self: "foo.comjira/rest/api/2/customFieldOption/12245", value: "No", id: "12245", disabled: !1},MissionConfigurationDefinition: [{self: "foo.comjira/rest/api/2/customFieldOption/12246", value: "1110-1200", id: "12246", disabled: !1},{self: "foo.comjira/rest/api/2/customFieldOption/12247", value: "1110-2200", id: "12247", disabled: !1}],updated: "2022-05-23T10: 06: 45.000-0500", description: "¶ Paragraph\nNonbreaking Hyphen\nEm Space\nEn Space\n½ One Half Fraction\n¼ One Quarter Fraction\n¾ Three Quarters Fraction\n10⁵ superscript\n6⁵ superscript\nO₂ subscript\n\n± 0177\n≤ 2264\n≥ 2265\n\n10⁰ - 2070\n10¹ - 00B9\n10³ - 00B3\n10² - 00B2\n10⁴ - 2074\n10⁵ - 2075\n10⁶ - 2076\n10⁷ - 2077\n10⁸ - 2078\n10⁹ - 2079\n\nΑ 0391\nΒ 0392\nΓ 0393\nΔ 0394\nΕ 0395", CRStatus: {self: "foo.comjira/rest/api/2/customFieldOption/10050", value: "In Work", id: "10050", disabled: !1},summary: "SLS-FSW-SAN-21-0010 SLS FSW Software Authorization Notice (SAN) - PARMD5 Support Tool Release 14.0", SLSPriority: {self: "foo.comjira/rest/api/2/customFieldOption/10347", value: "Routine", id: "10347", disabled: !1},TestStatus: [{self: "foo.comjira/rest/api/2/customFieldOption/10041", value: "Not Tested", id: "10041", disabled: !1}],ChangeJustificationRationale: "Looks good to me, but who am I?", CostImpact: {self: "foo.comjira/rest/api/2/customFieldOption/19251", value: "No", id: "19251", disabled: !1},ExternalReviewType: {self: "foo.comjira/rest/api/2/customFieldOption/10370", value: "Mandatory", id: "10370", disabled: !1},CROffice: {self: "foo.comjira/rest/api/2/customFieldOption/10342", value: "SLS", id: "10342", disabled: !1},Rank: "0|i0c9r8: ", CrossProgram: {self: "foo.comjira/rest/api/2/customFieldOption/10294", value: "No", id: "10294", disabled: !1},Programassignedto: {self: "foo.comjira/rest/api/2/customFieldOption/10295", value: "SLS", id: "10295", disabled: !1},Programassignedby: {self: "foo.comjira/rest/api/2/customFieldOption/10301", value: "SLS", id: "10301", disabled: !1},ChangeType: [{self: "foo.comjira/rest/api/2/customFieldOption/10307", value: "Programmatic", id: "10307", disabled: !1}],ChangePackageManagerCPM: {self: "foo.comjira/rest/api/2/user?username=swchambe", name: "swchambe", key: "swchambe", emailAddress: "sharon.w.chamberlain#foo.com", displayName: "Sharon W Chamberlain", active: !0,timeZone: "America/Chicago"},ChangePackageManagerAlternateCPMAlternate: {self: "foo.comjira/rest/api/2/user?username=slcraig", name: "slcraig", key: "smclemo2", emailAddress: "shanda.craig#foo.com", displayName: "Shanda L Craig", active: !0,timeZone: "America/Chicago"},ChangePackageEngineerCPE: {self: "foo.comjira/rest/api/2/user?username=cbowab", name: "cbowab", key: "cbowab", emailAddress: "cheri.f.bowab#foo.com", displayName: "Cheri F Bowab", active: !0,timeZone: "America/Chicago"},status: {self: "foo.comjira/rest/api/2/status/10631", description: "", iconUrl: "foo.comjira/images/icons/statuses/generic.png", name: "Draft", id: "10631"},Development: "{}", RequestedDate: "2021-05-13", Risk: {self: "foo.comjira/rest/api/2/customFieldOption/10273", value: "No", id: "10273", disabled: !1},creator: {self: "foo.comjira/rest/api/2/user?username=djcook2", name: "djcook2", key: "djcook2", emailAddress: "deborah.j.ott#foo.com", displayName: "Deborah Jane Ott", active: !0,timeZone: "America/Chicago"},aggregateprogress: {progress: 0,total: 0},AssigneeSecurityScan: {self: "foo.comjira/rest/api/2/user?username=sbattles", name: "sbattles", key: "sbattles", emailAddress: "sylvia.battles#foo.com", displayName: "Sylvia M Battles", active: !0,timeZone: "America/Chicago"},Board: [{self: "foo.comjira/rest/api/2/customFieldOption/10259", value: "XYZ", id: "10259", disabled: !1}],MissionEffectivity: [{self: "foo.comjira/rest/api/2/customFieldOption/19754", value: "XYZ", id: "19754", disabled: !1},{self: "foo.comjira/rest/api/2/customFieldOption/19756", value: "AC01", id: "19756", disabled: !1}],CRNumber: [{name: "XYZ-0637"}],created: "2021-05-14T15: 14: 22.000-0500", ASCBBoardDate: "2021-05-18", InitiatorOrganization: "ED10", CPMAssignedDate: "2021-05-14", CRAssignedDate: "2021-05-14", ImpactstoCertifiedData: {self: "foo.comjira/rest/api/2/customFieldOption/20152", value: "No", id: "20152", disabled: !1},ASCBReviewSuspenseDate: "2021-05-18", TopLevelLinkTitle: "SV02854 S2D-0637", TopLevelLinkURL: "https: //nasa-ice.nasa.gov/Windchill/app/#ptc1/tcomp/infoPage?ContainerOid=OR%3Awt.inf.library.WTLibrary%3A3451955009&oid=OR%3Awt.folder.SubFolder%3A4352888087&u8=1", Initiator: {self: "foo.comjira/rest/api/2/user?username=kmoorhea", name: "kmoorhea", key: "kmoorhea", emailAddress: "kathy.h.moorhead#foo.com", displayName: "Kathy H Moorhead", active: !0,timeZone: "America/Chicago"}}}]}}
console .log (convert (input))
.as-console-wrapper {max-height: 100% !important; top: 0}
Here, makeFancyMenu does all the recursive heavy lifting, and convert simply wraps it in something that handles the differences at the root.
Instead of map we use flatMap and wrap its single callback returns in arrays so that in the case of an array property, we can just return an empty array. This is a simple way to combine filter and map.
I have an array of object that defines file and directory structure. It will vary according to reality, which may be more complicated.
Here is an example :
For example this root folder contains "folder_id": "F1" and "folder_id": "F2", and it will continue to divide ...
const folders = [
{
folder_id: "F1",
name: "Test Folder 1",
files: [
{
file_id: "File1",
name: "Whiteboard-Jun 3rd 2020, 4:56 pm"
}
],
folders: [
{
folder_id: "Folder1",
name: "Sub Folder",
files: [
{
file_id: "File1-1",
name: "New Microsoft Word Document.docx"
}
],
folders: [
{
folder_id: "Folder1-1",
name: "Folder Grade 2",
files: [
{
file_id: "File1-1-1",
name: "Test file in Folder Grade 3"
}
],
folders: [
{
folder_id: "Folder1-1-1",
name: "Folder Grade 3",
files: [],
folders: []
}
]
}
]
}
]
},
{
folder_id: "F2",
name: "Test Folder 2",
files: [
{
file_id: "File2",
name: "buildcode.png"
}
],
folders: [
{
folder_id: "Folder2",
name: "Sub folder 1",
files: [
{
file_id: "File2-1",
name: "repo.png"
}
],
folders: []
}
]
}
];
I want the output to look like this:
{
my-root-id:{
childrenIds:[
0: "F1",
1: "F2"
],
id: "my-root-id"
},
F1:{
childrenIds:[
0: "File1",
1: "Folder1"
],
parentId: "my-root-id",
id: "F1"
},
F2:{
childrenIds:[
0: "File2",
1: "Folder2"
],
parentId: "my-root-id",
id: "F2"
},
File1:{
parentId: "File1",
id: "F1"
},
Folder1:{
childrenIds:[
0: "File1-1",
1: "Folder1-1"
],
parentId: "F1",
id: "Folder1"
},
Folder1-1:{
childrenIds:[
0: "File1-1-1",
1: "Folder1-1-1"
],
parentId: "Folder1",
id: "Folder1-1"
},
Folder2:{
childrenIds:[
0: "File2-1",
],
parentId: "F2",
id: "Folder2"
},
File2-1:{
parentId: "Folder2",
id: "File2-1"
}
}
The output above describes the relationship of each folder and file in the entire directory tree.
They need information like :
childrenIds: the folders and files it contains
parentId: Its parent directory
id: id by itself
How to do it. thank you
Don't know this actually works for you or not but output as you look for
let data = {
folders: [
{
folder_id: "F1",
name: "Test Folder 1",
files: [
{
file_id: "File1",
name: "Whiteboard-Jun 3rd 2020, 4:56 pm",
},
],
folders: [
{
folder_id: "Folder1",
name: "Sub Folder",
files: [
{
file_id: "File1-1",
name: "New Microsoft Word Document.docx",
},
],
folders: [
{
folder_id: "Folder1-1",
name: "Folder Grade 2",
files: [
{
file_id: "File1-1-1",
name: "Test file in Folder Grade 3",
},
],
folders: [
{
folder_id: "Folder1-1-1",
name: "Folder Grade 3",
files: [],
folders: [],
},
],
},
],
},
],
},
{
folder_id: "F2",
name: "Test Folder 2",
files: [
{
file_id: "File2",
name: "buildcode.png",
},
],
folders: [
{
folder_id: "Folder2",
name: "Sub folder 1",
files: [
{
file_id: "File2-1",
name: "repo.png",
},
],
folders: [],
},
],
},
],
};
const mapper = (folders, parentId) => {
let obj = {};
if (folders.length) {
folders.forEach((f) => {
if (f.folders) {
let _c = {
[f.folder_id]: {
childrenIds: f.files.map((_f) => _f.file_id),
...(parentId && { parentId }),
id: f.folder_id,
},
};
let _files = f.files.map((_f) => {
return {
[_f.file_id]: { ...(parentId && { parentId }), id: _f.file_id },
};
});
obj = { ...obj, ..._files["0"], ..._c, ...mapper(f.folders, f.folder_id) };
}
});
}
return obj;
};
console.log(mapper(data.folders));