Search code examples
javascriptarraysnested

Nested array of objects to filter through , set properties then return parents recursively


So I have this list of nested objects that I'm supposed to show in a web interface,

The nesting can go up to 4 levels deep

I need to filter it based on an object property (let's say owner_id).

The filter should recursively return parents if a child is nested inside while checking if it's a target object: set a property .filtered=true to it, if it is a parent: let's say we set parent=true to it.

The display depends on those properties in order to expand or collapse parents and highlight filtered ones using a different color

(Quick side note: everything has an id, and I have access to a flat version of the objects array without nesting)

My objects structure:

let objs =
[
    {
        title: 'title.1',
        owner_id: 1
        child_cards: [
            {
                title: 'title.1.1',
                owner_id: 2
                child_cards: [
                    {
                        title: 'title.1.1.1',
                        owner_id: 1,
                    },
                    {
                        title: 'title.1.1.2',
                        owner_id: 2
                    },
                ]
            },
            {
                title: 'title.1.2',
                owner_id: 2,
                child_cards: [
                    {
                        title: 'title.1.2.1',
                        owner_id: 1,
                    },
                ]
            },
        ]
    },
    {
        title: 'title.2',
        owner_id: 3
        child_cards: [
            {
                title: 'title.2.1',
                owner_id: 2
            }
        ]
    },
    {
        title: 'title.3',
        owner_id: 1,
        child_cards: [
            {
                title: 'title.3.1',
                owner_id: 1
            },
            {
                title: 'title.3.2',
                owner_id: 1
            },
            {
                title: 'title.3.3',
                owner_id: 1
            }
        ]
    }
]

Example calling it with owner_id=2:

[
    {
        title: 'title.1',
        owner_id: 1,
        parented: true,
        child_cards: [
            {
                title: 'title.1.1',
                owner_id: 2,
                parented: true,
                filtered: true,
                child_cards: [
                    {
                        title: 'title.1.1.2',
                        owner_id: 2,
                        filtered: true
                    },
                ]
            },
            {
                title: 'title.1.2',
                owner_id: 2,
                filtered: true,
                child_cards: [
                    {
                        title: 'title.1.2.1',
                        owner_id: 1,
                    },
                ]
            },
        ]
    },
    {
        title: 'title.2',
        owner_id: 3,
        parented: true,
        child_cards: [
            {
                title: 'title.2.1',
                owner_id: 2,
                filtered: true
            }
        ]
    }
]

Somehow every solution I found on StackOverflow doesn't include my case where I need to set specific properties to children/parents or the algorithm instantly ignores any other child if it only finds one occurrence.

Any help is appreciated! 😁


Solution

  • I think this function solves the problem:

        const source =
        [
            {
                title: 'title.1',
                owner_id: 1,
                child_cards: [
                    {
                        title: 'title.1.1',
                        owner_id: 2,
                        child_cards: [
                            {
                                title: 'title.1.1.1',
                                owner_id: 1,
                            },
                            {
                                title: 'title.1.1.2',
                                owner_id: 2
                            },
                        ]
                    },
                    {
                        title: 'title.1.2',
                        owner_id: 2,
                        child_cards: [
                            {
                                title: 'title.1.2.1',
                                owner_id: 1,
                            },
                        ]
                    },
                ]
            },
            {
                title: 'title.2',
                owner_id: 3,
                child_cards: [
                    {
                        title: 'title.2.1',
                        owner_id: 2
                    }
                ]
            },
            {
                title: 'title.3',
                owner_id: 1,
                child_cards: [
                    {
                        title: 'title.3.1',
                        owner_id: 1
                    },
                    {
                        title: 'title.3.2',
                        owner_id: 1
                    },
                    {
                        title: 'title.3.3',
                        owner_id: 1
                    }
                ]
            }
        ]
    
        const treatNode = (node, name, value) => {
    
          const filtered = node[name] == value
          const children = node.child_cards ? node.child_cards.map(x => treatNode(x, name, value)) : [];
          const filtered_children = children.filter(x => x.filtered || x.parent);
          const parent = filtered_children.length > 0;
          
          let ret = {...node};
          delete ret.child_cards;
          if (filtered) ret = {...ret, filtered: true};
          if (parent) ret = {...ret, parent: true};
          if (filtered_children.length > 0)
            ret = {...ret, child_cards: filtered_children};
          
          return ret;
        }
    
        console.log(source.map(x => treatNode(x, "owner_id", 2)).filter(x => x.filtered || x.parent))

    Please let me know if is it what you are looking for.