skip to Main Content

how does one go about inserting an item into a nested javascript array of objects (with and without using a library)? running to a problem where once you insert the item after traversing, how would you reassign it back to the original object without manually accessing the object like data.content[0].content[0].content[0] etc..? already tried Iterate through Nested JavaScript Objects but could not get the reassignment to work

const data = {
    "content": [
        {
            "name": "a",
            "content": [
                {
                    "name": "b",
                    "content": [
                        {
                            "name": "c",
                            "content": []
                        }
                    ]
                }
            ]
        }
    ]
}

inserting {"name": "d", "content": []} into the contents of c

const data = {
    "content": [
        {
            "name": "a",
            "content": [
                {
                    "name": "b",
                    "content": [
                        {
                            "name": "c",
                            "content": [{"name": "d", "content": []}]
                        }
                    ]
                }
            ]
        }
    ]
}

2

Answers


  1. const data = {
      "content": [{
        "name": "a",
        "content": [{
          "name": "b",
          "content": [{
            "name": "c",
            "content": []
          }]
        }]
      }]
    }
    
    const insert = createInsert(data)
    
    insert({
      "name": "d",
      "content": []
    }, 'c')
    
    console.log(data)
    
    // create a new function that will be able to insert items to the object
    function createInsert(object) {
      return function insert(obj, to) {
        // create a queue with root data object
        const queue = [object]
        // while there are elements in the queue
        while (queue.length) {
          // remove first element from the queue
          const current = queue.shift()
          // if name of the element is the searched one
          if (current.name === to) {
            // push the object into the current element and break the loop
            current.content.push(obj)
            break
          }
          // add child elements to the queue
          for (const item of current.content) {
            queue.push(item)
          }
        }
      }
    }
    Login or Signup to reply.
  2. It looks like we should assume that the name property uniquely identifies an object in the data structure. With that assumption you could create a mapping object for it, so to map a given name to the corresponding object in the nested structure. Also keep track which is the parent of a given object.

    All this meta data can be wrapped in a decorator function, so that the data object gets some capabilities to get, add and remove certain names from it, no matter where it is in the hierarchy:

    function mappable(data) {
        const map = { "__root__": { content: [] } };
        const parent = {};
        const dfs = (parentName, obj) => {
            parent[obj.name] = parentName;
            map[obj.name] = obj;
            obj.content?.forEach?.(child => dfs(obj.name, child));
        }
        
        Object.defineProperties(data, {
            get: { value(name) {
                 return map[name];
            }},
            add: { value(parentName, obj) {
                this.get(parentName).content.push(obj);
                dfs(parentName, obj);
            }},
            remove: { value(name) {
                map[parent[name]].content = map[parent[name]].content.filter(obj =>
                    obj.name != name
                );
                delete map[name];
                delete parent[name];
            }}
        });
        data.add("__root__", data);
    }
    
    // Demo
    const data = {"content": [{"name": "a","content": [{"name": "b","content": [{"name": "c","content": []}]}]}]};
    
    mappable(data);
    data.add("c", { name: "d", content: [] });
    console.log(data);
    console.log(data.get("d")); // { name: "d", content: [] }
    data.remove("d");
    console.log(data.get("d")); // undefined
    console.log(data); // original object structure
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search