Reputation: 2463
Good evening.
I have the following JSON. Where I'd like path
to contain the position in the tree using the url
property and keeping in mind it can be nested deep. I have added some comments but I'm aware this is never possible in plain JSON. :)
[
{
"url": "articles",
"path": "...", // should become path: "articles"
"subitems": [
{
"url": "article-one",
"path": "...", // should become path: "articles/article-one"
"subitems": []
},
{
"url": "article-two",
"path": "...",
"subitems": []
},
]
},
{
"url": "homepage",
"path": "...",
"subitems": []
},
{
"url": "home",
"path": "...", // should become path: "home"
"subitems": [
{
"url": "maintenance",
"path": "...", // should become path: "home/maintenance"
"subitems": []
},
{
"url": "customer-service",
"path": "...",
"subitems": []
},
{
"url": "news",
"path": "...", // should become path: "home/news"
"subitems": [
{
"url": "news-item-1", // should become path: "home/news/news-item-1"
"path": "...",
"subitems": []
}
]
}
]
}
]
Can someone help me with this?
Thank you so much!
Upvotes: 0
Views: 320
Reputation: 2181
Here is an iterative solution using object-scan
// const objectScan = require('object-scan');
const data = [{ url: 'articles', subitems: [{ url: 'article-one', subitems: [] }, { url: 'article-two', subitems: [] }] }, { url: 'homepage', subitems: [] }, { url: 'home', subitems: [{ url: 'maintenance', subitems: [] }, { url: 'customer-service', subitems: [] }, { url: 'news', subitems: [{ url: 'news-item-1', subitems: [] }] }] }];
const inject = objectScan(['**(^subitems$).url'], {
useArraySelector: false,
rtn: 'count',
filterFn: ({ parents }) => {
parents[0].path = parents
.reverse()
.filter((e) => !Array.isArray(e))
.map(({ url }) => url)
.join('/');
}
});
console.log(inject(data));
// => 9
console.log(data);
// => [ { url: 'articles', subitems: [ { url: 'article-one', subitems: [], path: 'articles/article-one' }, { url: 'article-two', subitems: [], path: 'articles/article-two' } ], path: 'articles' }, { url: 'homepage', subitems: [], path: 'homepage' }, { url: 'home', subitems: [ { url: 'maintenance', subitems: [], path: 'home/maintenance' }, { url: 'customer-service', subitems: [], path: 'home/customer-service' }, { url: 'news', subitems: [ { url: 'news-item-1', subitems: [], path: 'home/news/news-item-1' } ], path: 'home/news' } ], path: 'home' } ]
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/[email protected]"></script>
Disclaimer: I'm the author of object-scan
Upvotes: 0
Reputation: 122057
You could do this with recursive function and add path
property when the current element in the for...in
loop is object (typeof object
and not Array.isArray
)
const data = [{"url":"articles","subitems":[{"url":"article-one","subitems":[]},{"url":"article-two","subitems":[]}]},{"url":"homepage","subitems":[]},{"url":"home","subitems":[{"url":"maintenance","subitems":[]},{"url":"customer-service","subitems":[]},{"url":"news","subitems":[{"url":"news-item-1","subitems":[]}]}]}]
function addPath(data, prev = '') {
for (let i in data) {
if (typeof data[i] === 'object') {
let path = prev;
if (!Array.isArray(data[i])) {
data[i].path = path += (path ? '/' : '') + data[i].url
}
addPath(data[i], path)
}
}
}
addPath(data);
console.log(data)
Upvotes: 1