-1

I'm trying to extract objects that are within an array whose name property includes a keyword. I can do this by iterating through my array but I wanted to see if there's a more efficient way to do this.

Here's what my array and objects within it look like:

[
  {
     "accountId": 123,
     "items": [
        {
           "id": 1,
           "name": "Property XYZ"
        },
        {
           "id": 2,
           "name": "Gadget 1"
        }
     ]
  },
  {
     "accountId": 234,
     "items": [
        {
           "id": 7,
           "name": "Property ABC"
        },
        {
           "id": 8,
           "name": "Property QWERTY"
        }
     ]
  }
]

There are two objectives, one a bit simpler:

  1. I'd like to return only those objects whose name property includes the keyword "Property"
  2. Same criteria as above but I'd like to include return the parent object that contains the object I'm looking for.

So, the output for the first requirement would look like this:

[
   {
      "id": 1,
      "name": "Property XYZ"
   },
   {
      "id": 7,
      "name": "Property ABC"
   },
   {
      "id": 8,
      "name": "Property QWERTY"
   }
]

And the output for the second requirement would look like this:

[
   {
      "accountId": 123,
      "items": [
         {
            "id": 1,
            "name": "Property XYZ"
         }
      ]
   },
   {
      "accountId": 234,
      "items": [
         {
            "id": 7,
            "name": "Property ABC"
         },
         {
            "id": 8,
            "name": "Property QWERTY"
         }
      ]
   }
]

Is there another way than iterating through the whole array and pushing copies of objects that I'm looking for into a new array?

Sam
  • 26,817
  • 58
  • 206
  • 383

1 Answers1

1

Javascript array methods are very powerful, and you can get both of your results pretty easily by chaining them. The ones that will be most useful here will be:

  • flatMap for building the array of "items" from your original list.
  • map for the same as above but when we don't need to flatten the result array.
  • filter for removing items that don't meet your condition.

With that, your first condition can be done with the following steps:

  1. Construct a list of just your "items" from each of the parents.
  2. Filter that list to only include those that meet your condition.

For the second, you can do:

  1. Make a new array with copies of the parents, but where the items of each are filtered to only those that meet your condition.
  2. Filter out parents that don't have any items left after the above step.

Thus, for this you can write these two new arrays quite concisely:

const myArray = [{
  "accountId": 123,
  "items": [{
    "id": 1,
    "name": "Property XYZ"
  }, {
    "id": 2,
    "name": "Gadget 1"
  }]
}, {
  "accountId": 234,
  "items": [{
    "id": 7,
    "name": "Property ABC"
  }, {
    "id": 8,
    "name": "Property QWERTY"
  }]
}]

// Only those objects whose name property includes the keyword "Property".
const onlyWithProperty = myArray
    .flatMap(elem => elem.items)
    .filter(item => item.name.includes("Property"))

// Only those parent objects who have an item whose name property includes the keyword "Property".
const onlyParentsWithProperty = myArray
    .map(elem => ({...elem, items: elem.items.filter(item => item.name.includes("Property"))}))
    .filter(elem => elem.items.length);

console.log("First req:", onlyWithProperty);
console.log("Second req:", onlyParentsWithProperty);
CRice
  • 29,968
  • 4
  • 57
  • 70
  • Thank you! Very powerful indeed! One follow up question: both `onlyWithProperty` and `onlyParentsWithProperty` are new arrays correct? Meaning, they don't affect any of the values in the original `myArray`. – Sam Jun 16 '20 at 19:07
  • Actually, I see the answer in the documentation. They are new arrays. Thanks again! – Sam Jun 16 '20 at 19:08
  • 1
    Yes and no. The arrays themselves are shallow copies. Changing the arrays themselves won't modify the original, but mutating the *items* in the array will also mutate the original items. [This question might help](https://stackoverflow.com/questions/518000/is-javascript-a-pass-by-reference-or-pass-by-value-language). – CRice Jun 16 '20 at 19:11
  • Got it. Thanks again! – Sam Jun 16 '20 at 19:13