简体   繁体   中英

Find deeply nested JSON property using lodash

I have a JSON API response with the following structure

[
  {
    title: "top1",
    sections: [
      {
        section_title: "section1",
        content: [
          {
            content_title: "title1",
            content_id: "id1"
          },
          {
            content_title: "title2",
            content_id: "id2"
          }
        ]
      },
      {
        section_title: "section2",
        content: [
          {
            content_title: "title3",
            content_id: "id3"
          },
          {
            content_title: "title4",
            content_id: "id4"
          }
        ]
      }
    ]
  }, {
    title: "top2",
    sections: [...]
  },
  ...
]

I also have a small array of content IDs arr2 = ['id2','id3'] . I need to search the data from the API request to find any content_id that is contained in arr2 .

I have some working lodash code, but my approach of nested forEach does not seem to be the most efficient approach:

_.forEach(response, function(top) {
  _.forEach(top.sections, function(section) {
    _.forEach(section.content, function(content) {
      _.forEach(arr2, function(id) {
        if(id === content.content_id) {
         // Do stuff
        }
      })
    })
  })
})

How could I improve this code?

After a little thought, I actually can't come up with a more elegant solution using other lodash functions for you. It seems that to set the owned properties for each and every case the forEach is the way to go. The only optimisation I can make is to avoid using lodash simply by using the vanilla javascript forEach Array function, and use find to replace the innermost forEach (might make a slight performance improvement).

response.forEach((topItem) => {
    topItem.sections.forEach((section) => {
        section.content.forEach((content) => {
            if(arr2.find((item) => { return item === content.content_id; })){
                topItem.owned = true; section.owned = true; content.owned = true;
            }
        });
    });
});

I have a personal preference for arrow function syntax also...

You can create a function that recursively iterates over recognized descendant properties.

function deepWalk(collection, childKeys, iteratee) {

  // create a partial _.each with an iterator that will
  // recursively traverse properties from the `childKeys` array
  var each = _.partial(_.each, _, function(value, index) {
    // invoke iteratee callback
    iteratee(value, index);
    // only recursively iterate over properties found in childKeys
    _(value).pick(childKeys).each(each);
  });

  // invoke iteration
  each(collection);

}

deepWalk(collection, ['sections', 'content'], function(value) {
  if(_.includes(['id2', 'id3'], value.content_id)) {
    // do whatever you want here..
    console.log(value);
  }
});

 var collection = [ { title: "top1", sections: [ { section_title: "section1", content: [ { content_title: "title1", content_id: "id1" }, { content_title: "title2", content_id: "id2" } ] }, { section_title: "section2", content: [ { content_title: "title3", content_id: "id3" }, { content_title: "title4", content_id: "id4" } ] } ] } ]; function deepWalk(collection, childKeys, iteratee) { // create a partial _.each with an iterator that will // recursively traverse properties from the `childKeys` array var each = _.partial(_.each, _, function(value, index) { // invoke iteratee callback iteratee(value, index); // only recursively iterate over properties found in childKeys _(value).pick(childKeys).each(each); }); // invoke iteration each(collection); } deepWalk(collection, ['sections', 'content'], function(value) { if(_.includes(['id2', 'id3'], value.content_id)) { // do whatever you want here.. console.log(value); } }); 
 .as-console-wrapper { min-height: 100%; top: 0; } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM