1

Given this structure, how would I find the object with the given id in this deeply nested object structure.

const menuItems = [
    {
        id: 1,
        imageUrl: "http://placehold.it/65x65",
        display: "Shop Women",
        link: "#",
        type: "image",
        nextItems: [
            {
                id: 10,
                display: "홈",
                link: "#",
                type: "menuitem"
            },
            {
                id: 20,
                display: "의류",
                link: "#",
                type: "menuitem-withmore",
                nextItems: [
                    {
                        id: 100,
                        display: "I'm inside one nest",
                        link: "#",
                        type: "menuitem"
                    }
                ]
            },
            {
                id: 30,
                display: "가방",
                link: "#",
                type: "menuitem-withmore",
                nextItems: []
            },
            {
                id: 40,
                display: "신발",
                link: "#",
                type: "menuitem-withmore",
                nextItems: []
            },
            {
                id: 50,
                display: "악세서리",
                link: "#",
                type: "menuitem-withmore",
                nextItems: []
            },
            {
                id: 60,
                display: "SALE",
                link: "#",
                type: "menuitem-withmore",
                style: "bold",
                nextItems: []
            },
            {
                id: 70,
                display: "브랜드",
                link: "#",
                type: "menuitem-withmore",
                nextItems: []
            },
            {
                type: "separator"
            },
            {
                id: 80,
                display: "위시리스트",
                link: "#",
                type: "menuitem"
            },
            {
                id: 90,
                display: "고객센터",
                link: "#",
                type: "menuitem"
            },
            {
                id: 99,
                display: "앱 다운로드",
                link: "#",
                type: "menuitem"
            }
        ]
    },
    {
        id: 2,
        imageUrl: "http://placehold.it/65x65",
        display: "Shop Men",
        link: "#",
        type: "image",
        nextItems: [
            {
                id: 95,
                display: "MEN's ITEMS.",
                link: "#",
                type: "menuitem"
            }
        ]
    }
];

Let's say I want to find the object with id: 20 and return this:

        {
            id: 20,
            display: "의류",
            link: "#",
            type: "menuitem-withmore",
            nextItems: [
                {
                    id: 100,
                    display: "I'm inside one nest",
                    link: "#",
                    type: "menuitem"
                }
            ]
        },

I can't seem to find how to use lodash for this, and there's this package that may have solved my issue but I couldn't understand how to make it work for my use case.

https://github.com/dominik791/obj-traverse

5
  • Do you want to find the item in menuList or nextItems? Commented Mar 15, 2018 at 20:22
  • Exactly what I posted in my return example. The object, along with any children it may have itself, like nextItems. Commented Mar 15, 2018 at 20:22
  • Duplicate of stackoverflow.com/questions/41610948/… Commented Mar 15, 2018 at 20:24
  • 1
    @JoeLafiosca Not a dupe - his question and answers only address 1 level deep. Commented Mar 15, 2018 at 20:26
  • The findAll answer goes further than 1 level deep, but the same principles of iteration apply regardless. If you'd like to roll your own solution though, you could use recursion as demonstrated in the DFS answer from Kevin Qian below. Commented Mar 15, 2018 at 20:31

5 Answers 5

12

Use DFS.

const menuItems = [
    {
        id: 1,
        imageUrl: "http://placehold.it/65x65",
        display: "Shop Women",
        link: "#",
        type: "image",
        nextItems: [
            {
                id: 10,
                display: "홈",
                link: "#",
                type: "menuitem"
            },
            {
                id: 20,
                display: "의류",
                link: "#",
                type: "menuitem-withmore",
                nextItems: [
                    {
                        id: 100,
                        display: "I'm inside one nest",
                        link: "#",
                        type: "menuitem"
                    }
                ]
            },
            {
                id: 30,
                display: "가방",
                link: "#",
                type: "menuitem-withmore",
                nextItems: []
            },
            {
                id: 40,
                display: "신발",
                link: "#",
                type: "menuitem-withmore",
                nextItems: []
            },
            {
                id: 50,
                display: "악세서리",
                link: "#",
                type: "menuitem-withmore",
                nextItems: []
            },
            {
                id: 60,
                display: "SALE",
                link: "#",
                type: "menuitem-withmore",
                style: "bold",
                nextItems: []
            },
            {
                id: 70,
                display: "브랜드",
                link: "#",
                type: "menuitem-withmore",
                nextItems: []
            },
            {
                type: "separator"
            },
            {
                id: 80,
                display: "위시리스트",
                link: "#",
                type: "menuitem"
            },
            {
                id: 90,
                display: "고객센터",
                link: "#",
                type: "menuitem"
            },
            {
                id: 99,
                display: "앱 다운로드",
                link: "#",
                type: "menuitem"
            }
        ]
    },
    {
        id: 2,
        imageUrl: "http://placehold.it/65x65",
        display: "Shop Men",
        link: "#",
        type: "image",
        nextItems: [
            {
                id: 95,
                display: "MEN's ITEMS.",
                link: "#",
                type: "menuitem"
            }
        ]
    }
];

function dfs(obj, targetId) {
  if (obj.id === targetId) {
    return obj
  }
  if (obj.nextItems) {
    for (let item of obj.nextItems) {
      let check = dfs(item, targetId)
      if (check) {
        return check
      }
    }
  }
  return null
}

let result = null

for (let obj of menuItems) {
  result = dfs(obj, 100)
  if (result) {
    break
  }
}

console.dir(result)

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

3 Comments

What is DFS? Is that a lib or something?
@SergioTapia Depth First Search, a basic algorithm, basically recurse as deep as possible, if not found, backtrack one level and search for another, until found. See en.wikipedia.org/wiki/Depth-first_search
If we are talking algorithms why not just use a binary search tree? I thought simplicity here with my lodash answer yet nobody seemed to prefer.
2

You may try this function, it will work with a dynamic change of the deep level

function findNodeById(nodes, id, callback?) {
  let res;

  function findNode(nodes, id) {

    for (let i = 0; i < nodes.length; i++) {
      if (nodes[i].id === id) {
        res = nodes[i];
        // you can also use callback back here for more options ;)
        // callback(nodes[i]);
        break;
      }
      if (nodes[i].nextItems) {
        findNode(nodes[i].nextItems, id);
      }
    }
  }

  findNode(nodes, id)

  return res;
}

findNodeById(menuItems, 99) // { id: 99, display: "앱 다운로드", link: "#", type: "menuitem" }

Comments

1

I would do it

		const menuItems = [
			{
				id: 1,
				imageUrl: "http://placehold.it/65x65",
				display: "Shop Women",
				link: "#",
				type: "image",
				nextItems: [
					{
						id: 10,
						display: "홈",
						link: "#",
						type: "menuitem"
					},
					{
						id: 20,
						display: "의류",
						link: "#",
						type: "menuitem-withmore",
						nextItems: [
							{
								id: 100,
								display: "I'm inside one nest",
								link: "#",
								type: "menuitem"
							}
						]
					},
					{
						id: 30,
						display: "가방",
						link: "#",
						type: "menuitem-withmore",
						nextItems: []
					},
					{
						id: 40,
						display: "신발",
						link: "#",
						type: "menuitem-withmore",
						nextItems: []
					},
					{
						id: 50,
						display: "악세서리",
						link: "#",
						type: "menuitem-withmore",
						nextItems: []
					},
					{
						id: 60,
						display: "SALE",
						link: "#",
						type: "menuitem-withmore",
						style: "bold",
						nextItems: []
					},
					{
						id: 70,
						display: "브랜드",
						link: "#",
						type: "menuitem-withmore",
						nextItems: []
					},
					{
						type: "separator"
					},
					{
						id: 80,
						display: "위시리스트",
						link: "#",
						type: "menuitem"
					},
					{
						id: 90,
						display: "고객센터",
						link: "#",
						type: "menuitem"
					},
					{
						id: 99,
						display: "앱 다운로드",
						link: "#",
						type: "menuitem"
					}
				]
			},
			{
				id: 2,
				imageUrl: "http://placehold.it/65x65",
				display: "Shop Men",
				link: "#",
				type: "image",
				nextItems: [
					{
						id: 95,
						display: "MEN's ITEMS.",
						link: "#",
						type: "menuitem"
					}
				]
			}
		];

		var data = [];

		menuItems.forEach(function(item) {
			item.nextItems.forEach(function(element) {
				data.push(element)
			}, this);
		}, this);
    
	console.log(_.where(data, {id: 20}));
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>

Comments

1

Maybe this helps

menuItems.map(item => {
    if (item.id === 10) return item;
});

BTW I didn't consider efficiency in this solution.

Comments

-4

If you're using lodash, you just want the .find(collection, [predicate=.identity]).
So you'd want something like so:

_.find(menuItems, function(item) {
   return item.id = 20;
});

2 Comments

Does this go down deep through everything? If so, this is too good to be true haha
The item itself is another collection. There are a lot of functions that you can use to pull out whatever you want. _.get, helps with null references, _.find, etc. I don't know why I got negative ticks here. But you said lodash so I tried. Lol, Welcome to StackOverflow where ever character matters lol

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.