TransWikia.com

Get to deeply nested object by array path of ids

Stack Overflow Asked by rgc998 on November 7, 2021

I have this JSON data which has questions with options and questions nested in them. So the user picks an answer and the next question is chosen based on that answer and so on…. I have an array that is essentially a path (of ids) to the specific question object I’m looking for. How can I get to that object using my array of paths in my react component?

path = ["525289", "128886", "123456", "7547", "35735"] 

{"question": {
    "id":"525289",
    "options": [
       {
           "id":"128886",
           "optionName":{"alt":"123"},
            "question": {
                "id":"123456",
                "title": "soidjfs",
                 "options": [
                        {
                            "id":"7547",
                            "optionName":{"alt":"new"},
                                "question": {
                                    "id":"35735",
                                    "title": "soidjfs",
                                    "options": [
                                        
                                    ]
                                }
                        },
                        {
                            "id":"1234",
                            "optionName":{"alt":"new"},
                                "question": {
                                    "id":"25825",
                                    "title": "soidjfs",
                                    "options": [
                                        
                                    ]
                                }
                        }
                 ]
            }
       },
       {
           "id":"1234569999",
           "optionName":{"alt":"123"},
            "question": {
                "id":"3457",
                "title": "soidjfs",
                 "options": [
                        {
                            "id":"999998",
                            "optionName":{"alt":"new"},
                                "question": {
                                    "id":"2134678",
                                    "title": "soidjfs",
                                    "options": [
                                        
                                    ]
                                }
                        },
                        {
                            "id":"55555",
                            "optionName":{"alt":"new"},
                                "question": {
                                    "id":"123456159",
                                    "title": "soidjfs",
                                    "options": [
                                        
                                    ]
                                }
                        }
                 ]
            }
       }
    ]
}
}

3 Answers

I think your approach to this question is wrong. I think a better way would be to define each question separately as their own object and then have arrays of nested objects.

var questionId1 = {}
var questionId2 = {}
var questionId3 = {}
var questionId4 = {}
var questionId5 = {}

questionId1.options = [questionId2, questionId3]
questionId2.options = [questionId4]
questionId4.options = [questionId5] 

Traversing things that way can make the idea of the path obsolete. You'd just need the name of the current question to display the options. When the next question is selected, the parent is no longer relevant, only its children matter.

Still, if you're stuck using this method for one reason or another, you can use the . notation to access nested elements inside of objects. In this case, it sounds like you're looking for each element's id and wanting the element's options object. Assuming you want the option that traverses the user's path and returns the options at the end of the path, you're going to need a lot of nested ifs to make sure that certain properties are there and that they're not empty and loops to go deeper into arrays.

Here's a fiddle that shows that method.

Answered by mostegg on November 7, 2021

This could be done with a path similar (although not too similar) to what you provide, using the reduce function although there are some inconsistencies in your examples. For example, question seems to have a 1:1 relationship with option, so it doesn't seem like it needs filtering on traversal?

Alternatively as Mitya stated, you can use a JSON querying library. These are much more general purpose and so will be more verbose than a bespoke solution with contextual knowledge of your data structures.

I've used a much more simple, recursive parent-children model here:

let data = [
    {
        id: "123",
        children: [
            {
                id: "456A",
                title: "xyz",
                children: [
                    {
                        id: "789AA",
                        message: "Foo"
                    },
                    {
                        id: "789AB",
                        message: "Bar"
                    }
                ]
            },
            {
                id: "456B",
                title: "abc",
                children: [
                    {
                        id: "789BA",
                        message: "Hello"
                    },
                    {
                        id: "789BB",
                        message: "World!"
                    }
                ]
            }
        ]
    }
];
let path1 = ["123", "456A", "789AA"];
let path2 = ["123", "456C", "789CA"]; // Invalid as 456C isn't a valid item at this point in the tree
let path3 = ["123", "456B", "789BB"];
function select(path, data) {
    return path.reduce((acc, v) => acc && acc.children.find(c => c.id === v), {children: data});
}
console.log(select(path1, data));
console.log(select(path2, data));
console.log(select(path3, data));

Output:

{ id: '789AA', message: 'Foo' }
undefined
{ id: '789BB', message: 'World!' }

Answered by Fabian Feary on November 7, 2021

If you're open to using a (small) library, you could use something like very own J-Path, which allows you to query and traverse an object (first argument) using XPath (second), which is normally used to query XML.

let item = jpath(object, 'question[id="525289"]/options/item[id="128886"]/question[id="123456"]/options/item[id="7547"]/question[id="35735"]');

Or, more simply, we could go straight to the target using the final ID:

let item = jpath(object, '//question[id="35735"]');

If you don't want a library, you'll need to step through the IDs manually and use a while loop until you find the data item you need.

Answered by Mitya on November 7, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP