Reputation: 63
{
"groups": [
{
"name": "Event",
"groups": [
{
"name": "Service",
"subscriptions": [
{
"topic": "SERVICE_STATUS_PRESETS"
},
{
"topic": "AIRCRAFT_ACTIVATION",
},
{
"topic": "OUT_OF_SERVICE",
}
]
}
]
},
{
"name": "Enquiries",
"groups": [
{
"name": "Service-related",
"subscriptions": [
{
"topic": "PROMO_CODES_REQUESTS",
}
]
}
]
}
],
"subscriptions": [
{
"topic": "BANNERS",
},
{
"topic": "DOCUMENTS",
},
{
"topic": "USER",
}
]
}
OK guys I have such JSON structure what I need is to: return all topics in array, in this example it will be:
["SERVICE_STATUS_PRESETS", "AIRCRAFT_ACTIVATION", "OUT_OF_SERVICE", "PROMO_CODES_REQUESTS", "BANNERS", "DOCUMENTS", "USER"]
I try recursive calls like this, though I only get last three records:
getRecursive() {
if (Array.isArray(data)) {
for (let i = 0; i < data.length; i++) {
if (data[i].subscriptions) {
return data[i].subscriptions.map((val: SubscriptionGroupDetails) => val.topic);
} else if (data[i].groups) {
return this.getAllTopics(data[i].groups);
}
}
}
if (data && data.groups) {
return this.getAllTopics(data.groups);
}
return data.subscriptions.map((val: SubscriptionGroupDetails) => val.topic);
}
Upvotes: 4
Views: 12579
Reputation: 2181
Here is a solution using object-scan
// const objectScan = require('object-scan');
const data = {"groups":[{"name":"Event","groups":[{"name":"Service","subscriptions":[{"topic":"SERVICE_STATUS_PRESETS"},{"topic":"AIRCRAFT_ACTIVATION"},{"topic":"OUT_OF_SERVICE"}]}]},{"name":"Enquiries","groups":[{"name":"Service-related","subscriptions":[{"topic":"PROMO_CODES_REQUESTS"}]}]}],"subscriptions":[{"topic":"BANNERS"},{"topic":"DOCUMENTS"},{"topic":"USER"}]};
const searchTopics = (obj) => objectScan(['**.topic'], { rtn: 'value' })(obj);
console.log(searchTopics(data));
/* => [
'USER',
'DOCUMENTS',
'BANNERS',
'PROMO_CODES_REQUESTS',
'OUT_OF_SERVICE',
'AIRCRAFT_ACTIVATION',
'SERVICE_STATUS_PRESETS'
] */
.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: 2
Reputation: 1617
This version that takes a functional approach if you are interested. There are others above but this is just another way to look at it.
const recursion = object => Object.entries(object).map(([a, b]) => {
if (a === 'topic') return b;
if (Array.isArray(b)) return b.map(recursion);
return [];
}).flat(Infinity);
recursion(obj);
Upvotes: 1
Reputation: 386883
You could take a recursive approach and check
topic
,function getTopics(object) {
if (!object || typeof object !== 'object') return [];
if ('topic' in object) return [object.topic];
return Object.values(object).reduce((r, v) => [...r, ...getTopics(v)], []);
}
var data = { groups: [{ name: "Event", groups: [{ name: "Service", subscriptions: [{ topic: "SERVICE_STATUS_PRESETS" }, { topic: "AIRCRAFT_ACTIVATION" }, { topic: "OUT_OF_SERVICE" }] }] }, { name: "Enquiries", groups: [{ name: "Service-related", subscriptions: [{ topic: "PROMO_CODES_REQUESTS" }] }] }], subscriptions: [{ topic: "BANNERS" }, { topic: "DOCUMENTS" }, { topic: "USER" }] },
result = getTopics(data);
console.log(result);
Upvotes: 5
Reputation: 5895
use this:
function getTopics(obj){
if(typeof obj !== 'object') return [];
if(obj.topic) return [obj.topic];
var res = [];
for(var i in obj){
res.push(...getTopics(obj[i]));
}
return res;
}
Working example:
const topics = {
"groups": [
{
"name": "Event",
"groups": [
{
"name": "Service",
"subscriptions": [
{
"topic": "SERVICE_STATUS_PRESETS"
},
{
"topic": "AIRCRAFT_ACTIVATION",
},
{
"topic": "OUT_OF_SERVICE",
}
]
}
]
},
{
"name": "Enquiries",
"groups": [
{
"name": "Service-related",
"subscriptions": [
{
"topic": "PROMO_CODES_REQUESTS",
}
]
}
]
}
],
"subscriptions": [
{
"topic": "BANNERS",
},
{
"topic": "DOCUMENTS",
},
{
"topic": "USER",
}
]
}
function getTopics(obj){
if(typeof obj !== 'object') return [];
if(obj.topic) return [obj.topic];
var res = [];
for(var i in obj){
res.push(...getTopics(obj[i]));
}
return res;
}
console.log(getTopics(topics));
Upvotes: 1
Reputation: 236
EDIT: Added another way of doing it with .reduce()
You can create an empty array of topics
and then navigate through your nested structure recursively, adding a topic each time you come across it, using the javascript .forEach() to cycle through any nested groups
or subscriptions
.
let topics = [];
let findTopics = obj => {
if (obj.groups) {
obj.groups.forEach(findTopics);
}
if (obj.subscriptions) {
obj.subscriptions.forEach(findTopics);
}
if (obj.topic) {
topics.push(obj.topic);
}
}
findTopics(data);
Or a possibly neater way using .reduce():
let findTopicsRecursive = (topics, obj) => {
if (obj.groups) {
topics = obj.groups.reduce(findTopicsRecursive, topics);
}
if (obj.subscriptions) {
topics = obj.subscriptions.reduce(findTopicsRecursive, topics);
}
if (obj.topic) {
topics.push(obj.topic);
}
return topics;
}
let findTopics = data => findTopicsRecursive([], data);
let topics = findTopics(data);
Upvotes: 0