0

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": []}]
                        }
                    ]
                }
            ]
        }
    ]
}
3
  • Have you looked into recursion? Commented Dec 20, 2022 at 21:37
  • It seems like this answer at your linked question directly addresses what you need to do. You just need to change label to name. Commented Dec 20, 2022 at 21:41
  • the problem isn't iterating or inserting, it's in reassigning the inserted object back to the original data structure (or new data structure) Commented Dec 20, 2022 at 21:54

2 Answers 2

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)
      }
    }
  }
}

Sign up to request clarification or add additional context in comments.

3 Comments

Shouldn't data be a function parameter as well?
@Barmar yes, but I don't like that, fixed with a different pattern
@Konrad nice could you explain this code? it works but i'm not able to understand why and how the original data is updated
1

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.